Android14 窗口显示过程分析3

10/30/2024

# 1. 回顾

之前的章节我们说过,整体上我们可以把 Activity 的显示过程划分为 5 个阶段:

  • 阶段一:Activity Window DecorView 的初始化
  • 阶段二:添加 Window,初始化窗口对应的 WindowState 对象并挂载到窗口树中,预测量 Window 尺寸
  • 阶段三:预测量 View 树,构建 SurfaceControl/Layer,测量窗口大小,Transaction 配置 Layer,初始化 BLASTBufferQueue
  • 阶段四:View 树的测量布局绘制
  • 阶段五:显示窗口

本节分析第三阶段。

# 2. requestLayout 实现整体分析

ViewRootImpl::setView 主要调用链如下:

ViewRootImpl::setView
   ViewRootImpl::requestLayout
        ViewRootImpl::scheduleTraversals             
            ViewRootImpl.TraversalRunnable::run             -- 异步操作 
               ViewRootImpl::doTraversal
                  ViewRootImpl::performTraversals
                    ViewRootImpl::measureHierarchy                  --3 步 预 measure ViewViewRootImpl::relayoutWindow                    --4 步:relayoutWindow
                        Session::relayout                               -- 远程调用,构建 SurfaceControl/Layer,测量窗口大小,Transaction 配置 Layer
                        ViewRootImpl::updateBlastSurfaceIfNeeded        -- 初始化 BLASTBufferQueue,构建 Surface         
                    ViewRootImpl::performMeasure                    --5 步:View 的 测量布局绘制  
                    ViewRootImpl::performLayout
                    ViewRootImpl::performDraw        
                    ViewRootImpl::createSyncIfNeeded                --6 步:通知 WMS,客户端已经完成绘制,可以显示 SurfaceSession.addToDisplayAsUser                           ---1 步:addWindow
   mWindowLayout.computeFrames                          ---2 步:预计算 Window 尺寸
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

本小节从 ViewRootImpl::requestLayout 开始分析:

// /frameworks/base/core/java/android/view/ViewRootImpl.java

    boolean mHandlingLayoutInLayoutRequest = false;

    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) { // 一个标准位,避免重复调用
            checkThread();  //
            mLayoutRequested = true;  // 标志位
            scheduleTraversals();
        }
    }

    void scheduleTraversals() {
        if (!mTraversalScheduled) {    //同样,避免重复调用
            mTraversalScheduled = true;
            // 主线程 Looper post 一个同步屏障
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();

            // 申请 Vsync 信号
            // 下一次 Vsync 会执行到 mTraversalRunnable
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            
            // 渲染部分需要仔细分析这两个方法
            // ? 通知 HardwareRenderer 新的一帧即将来临
            notifyRendererOfFramePending();
            // ? 请求绘制锁定
            pokeDrawLockIfNeeded();
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

这里通过 Choreographer.postCallback 注册一个回调 mTraversalRunnable,同时申请 Vsync 信号,下一次 Vsync-app 信号到来,执行到回调 mTraversalRunnable:

// /frameworks/base/core/java/android/view/ViewRootImpl.java
    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }

    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            // 移除同步屏障
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }

            // 核心方法!
            performTraversals();

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

performTraversals 这个方法很重要,却又巨长!

这里打个断点可以看到,App 冷启动到 performTraversals 的调用堆栈:

20241025144751

总结就是,主线程(main)的 Looper 回调到 TraversalRunnable 回调。和我们的分析是一致的。

接着看 performTraversals 的实现:

// /frameworks/base/core/java/android/view/ViewRootImpl.java

    private void performTraversals() {

        mLastPerformTraversalsSkipDrawReason = null;

        // 这个 mView 是通过 setView 方法传进来的,也就是 Activity 的根布局 DecorView,使用 final 修饰,以防在遍历过程中被修改
        final View host = mView;

        // ......

        //是否正在遍历
        mIsInTraversal = true;
        //是否需要马上绘制
        mWillDrawSoon = true;
        boolean cancelDraw = false;
        String cancelReason = null;
        boolean isSyncRequest = false;
        //视图大小改变
        boolean windowSizeMayChange = false;

        // 布局参数
        // x = 0,y = 0
        // width = -1,height = -1
        // type = BASE_APPLICATION
        // surfaceInsets (0,0,0,0)
        WindowManager.LayoutParams lp = mWindowAttributes;

        //窗口的期望宽度和高度
        int desiredWindowWidth;
        int desiredWindowHeight;

        // DecorView 是否可见
        final int viewVisibility = getHostVisibility();  // 0 也就是 VISIBLE
        
        // mFirst 表示当前窗口第一次调用 performTraversals
        // false
        final boolean viewVisibilityChanged = !mFirst
                && (mViewVisibility != viewVisibility || mNewSurfaceNeeded
                // Also check for possible double visibility update, which will make current
                // viewVisibility value equal to mViewVisibility and we may miss it.
                || mAppVisibilityChanged);

        mAppVisibilityChanged = false;

        // false
        final boolean viewUserVisibilityChanged = !mFirst &&
                ((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE));

        // false
        // 判断布局 LayoutParams 的 privateFlags 是否有 RIVATE_FLAG_OPTIMIZE_MEASURE 参数
        final boolean shouldOptimizeMeasure = shouldOptimizeMeasure(lp);

        WindowManager.LayoutParams params = null;

        // ? todo https://developer.android.google.cn/guide/practices/device-compatibility-mode?hl=zh-cn
        CompatibilityInfo compatibilityInfo =
                mDisplay.getDisplayAdjustments().getCompatibilityInfo();

        // ......

        // 用来保存窗口宽度和高度,来自于全局变量 mWinFrame,这个 mWinFrame 保存了窗口最新尺寸
        // 前面预测量 Window,窗口尺寸保存在 mWinFrame 中,预测量的结果一般就是屏幕尺寸
        // pixel6 上值是 (0, 0 - 1080, 2400)
        Rect frame = mWinFrame;

        //构造方法里 mFirst 赋值为 true,意思是第一次执行遍历

        if (mFirst) { // 进入

            mFullRedrawNeeded = true;
            mLayoutRequested = true;

            // 设备配置信息
            final Configuration config = getConfiguration();

            if (shouldUseDisplaySize(lp)) {
                // ......
            } else if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
                    || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
               // .....
            } else { // 走这个分支
                // After addToDisplay, the frame contains the frameHint from window manager, which
                // for most windows is going to be the same size as the result of relayoutWindow.
                // Using this here allows us to avoid remeasuring after relayoutWindow
                // 前面预测量的结果
                desiredWindowWidth = frame.width();  // 1080
                desiredWindowHeight = frame.height(); // 2400
            }

        // ......
        
        if (layoutRequested) {
            if (!mFirst) { // 不进入
                // ......
            }

            // 关注点1,以 window 想要的尺寸进行预测量 View 树
            // desiredWindowWidth 1080 前面判断得到的,来自 window 的预测量结果
            // desiredWindowHeight 2400 前面判断得到的,
            // 测量的结果保存在 ViewRootImpl 的成员 mMeasuredWidth 和 mMeasuredHeight 中,也就是 DecorView 的大小
            // shouldOptimizeMeasure false
            // Ask host how big it wants to be
            windowSizeMayChange |= measureHierarchy(host, lp, mView.getContext().getResources(),
                    desiredWindowWidth, desiredWindowHeight, shouldOptimizeMeasure);
            // 计算结果 mMeasuredWidth 1080  mMeasuredHeight 2400
        }

        // ......

       

        if (mFirst || windowShouldResize || viewVisibilityChanged || params != null
                || mForceNextWindowRelayout) { // 进入


            // ......

            mForceNextWindowRelayout = false;

            insetsPending = computesInternalInsets; //false

            if (mSurfaceHolder != null) { // 不进入
                mSurfaceHolder.mSurfaceLock.lock();
                mDrawingAllowed = true;
            }

            boolean hwInitialized = false;
            boolean dispatchApplyInsets = false;
            boolean hadSurface = mSurface.isValid();

            try {
                if (DEBUG_LAYOUT) {
                    Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" +
                            host.getMeasuredHeight() + ", params=" + params);
                }

                if (mFirst || viewVisibilityChanged) { // 进入
                    mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED;
                }

                // 关注点2,window 布局
                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);

                // ......
            } catch (RemoteException e) {
            } finally {
                if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
                    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                }
            }

            //......
            mAttachInfo.mWindowLeft = frame.left;
            mAttachInfo.mWindowTop = frame.top;

            // !!FIXME!! This next section handles the case where we did not get the
            // window size we asked for. We should avoid this by getting a maximum size from
            // the window session beforehand.
            if (mWidth != frame.width() || mHeight != frame.height()) {
                // 后续 measure 会用到 mWidth mHeight
                // frame 就是 mWinFrame, 来自 WMS 测量的结果
                mWidth = frame.width();
                mHeight = frame.height();
            }

            // ......
            if (!mStopped || mReportNextDraw) {
                if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()
                        || dispatchApplyInsets || updatedConfiguration) {

                    int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width,
                            lp.privateFlags);
                    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height,
                            lp.privateFlags);

                    if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed!  mWidth="
                            + mWidth + " measuredWidth=" + host.getMeasuredWidth()
                            + " mHeight=" + mHeight
                            + " measuredHeight=" + host.getMeasuredHeight()
                            + " dispatchApplyInsets=" + dispatchApplyInsets);

                    // 关注点3,正式 Measure View 树
                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);

                    // Implementation of weights from WindowManager.LayoutParams
                    // We just grow the dimensions as needed and re-measure if
                    // needs be
                    int width = host.getMeasuredWidth();
                    int height = host.getMeasuredHeight();
                    boolean measureAgain = false;

                    if (lp.horizontalWeight > 0.0f) {
                        width += (int) ((mWidth - width) * lp.horizontalWeight);
                        childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
                                MeasureSpec.EXACTLY);
                        measureAgain = true;
                    }
                    if (lp.verticalWeight > 0.0f) {
                        height += (int) ((mHeight - height) * lp.verticalWeight);
                        childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
                                MeasureSpec.EXACTLY);
                        measureAgain = true;
                    }

                    if (measureAgain) {
                        if (DEBUG_LAYOUT) Log.v(mTag,
                                "And hey let's measure once more: width=" + width
                                + " height=" + height);
                        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                    }

                    layoutRequested = true;
                }
            }
        } else {
            // Not the first pass and no window/insets/visibility change but the window
            // may have moved and we need check that and if so to update the left and right
            // in the attach info. We translate only the window frame since on window move
            // the window manager tells us only for the new frame but the insets are the
            // same and we do not want to translate them more than once.
            maybeHandleWindowMove(frame);
        }

        // ......

        final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
        boolean triggerGlobalLayoutListener = didLayout
                || mAttachInfo.mRecomputeGlobalAttributes;
        if (didLayout) {
            // 关注点4 布局
            performLayout(lp, mWidth, mHeight);

            // By this point all views have been sized and positioned
            // We can compute the transparent area

            // ......
        }

        // .....

        if (!cancelAndRedraw) {
            // A sync was already requested before the WMS requested sync. This means we need to
            // sync the buffer, regardless if WMS wants to sync the buffer.
            if (mActiveSurfaceSyncGroup != null) {
                mSyncBuffer = true;
            }

            // 关注点6,添加显示的回调
            createSyncIfNeeded();
            notifyDrawStarted(isInWMSRequestedSync());
            mDrewOnceForSync = true;

            // If the active SSG is also requesting to sync a buffer, the following needs to happen
            // 1. Ensure we keep track of the number of active syncs to know when to disable RT
            //    RT animations that conflict with syncing a buffer.
            // 2. Add a safeguard SSG to prevent multiple SSG that sync buffers from being submitted
            //    out of order.
            if (mActiveSurfaceSyncGroup != null && mSyncBuffer) {
                updateSyncInProgressCount(mActiveSurfaceSyncGroup);
                safeguardOverlappingSyncs(mActiveSurfaceSyncGroup);
            }
        }

        if (!isViewVisible) {
            mLastPerformTraversalsSkipDrawReason = "view_not_visible";
            if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                for (int i = 0; i < mPendingTransitions.size(); ++i) {
                    mPendingTransitions.get(i).endChangingAnimations();
                }
                mPendingTransitions.clear();
            }

            if (mActiveSurfaceSyncGroup != null) {
                mActiveSurfaceSyncGroup.markSyncReady();
            }
        } else if (cancelAndRedraw) {
            mLastPerformTraversalsSkipDrawReason = cancelDueToPreDrawListener
                ? "predraw_" + mAttachInfo.mTreeObserver.getLastDispatchOnPreDrawCanceledReason()
                : "cancel_" + cancelReason;
            // Try again
            scheduleTraversals();
        } else {
            if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                for (int i = 0; i < mPendingTransitions.size(); ++i) {
                    mPendingTransitions.get(i).startChangingAnimations();
                }
                mPendingTransitions.clear();
            }
            // 关注点 5
            if (!performDraw() && mActiveSurfaceSyncGroup != null) {
                // 关注点6 触发显示回调
                mActiveSurfaceSyncGroup.markSyncReady();
            }
        }

        // .....
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
  • 关注点1,performTraversals() 方法后的第一个阶段,它会对 View 树进行第一次测量。在此阶段中将会计算出 View 树为显示其内容所需的尺寸,即期望的窗口尺寸。(调用measureHierarchy())
  • 关注点2,布局窗口阶段:根据预测量的结果,通过 IWindowSession.relayout() 方法向WMS请求调整窗口的尺寸等属性,这将引发 WMS 对窗口进行重新布局,并将布局结果返回给 ViewRootImpl。(调用relayoutWindow())
  • 关注点3,最终测量阶段:预测量的结果是View树所期望的窗口尺寸。然而由于在WMS中影响窗口布局的因素很多,WMS不一定会将窗口准确地布局为View树所要求的尺寸,而迫于WMS作为系统服务的强势地位,View树不得不接受WMS的布局结果。因此在这一阶段,performTraversals()将以窗口的实际尺寸对View树进行最终测量。(调用performMeasure())
  • 关注点4,布局View树阶段:完成最终测量之后便可以对View树进行布局了。(调用performLayout())
  • 关注点5,绘制阶段:确定了控件的位置与尺寸后,便可以对View树进行绘制了。(调用performDraw())
  • 关注点6,显示窗口

# 3. 预测量 View 树

调用 measureHierarchy 预测量 View 树。

    // ......

        Rect frame = mWinFrame; // 前面预测量 Window 的结果

        //构造方法里 mFirst 赋值为 true,意思是第一次执行遍历

        if (mFirst) { // 进入

            mFullRedrawNeeded = true;
            mLayoutRequested = true;

            // 设备配置信息
            final Configuration config = getConfiguration();

            if (shouldUseDisplaySize(lp)) {
                // ......
            } else if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
                    || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
               // .....
            } else { // 走这个分支
                // After addToDisplay, the frame contains the frameHint from window manager, which
                // for most windows is going to be the same size as the result of relayoutWindow.
                // Using this here allows us to avoid remeasuring after relayoutWindow
                // 从前面预测量的结果取值
                desiredWindowWidth = frame.width();  // 1080
                desiredWindowHeight = frame.height(); // 2400
            }

    // ......
 windowSizeMayChange |= measureHierarchy(host, lp, mView.getContext().getResources(),
                    desiredWindowWidth, desiredWindowHeight, shouldOptimizeMeasure);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

可以看出,measureHierarchy 方法传入的期望值来自前面预测量的 Window 尺寸。

measureHierarchy 的具体实现如下:

    private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
            final Resources res, final int desiredWindowWidth, final int desiredWindowHeight,
            boolean forRootSizeOnly) {

        int childWidthMeasureSpec;
        int childHeightMeasureSpec;
        boolean windowSizeMayChange = false;

        if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag,
                "Measuring " + host + " in display " + desiredWindowWidth
                + "x" + desiredWindowHeight + "...");

        boolean goodMeasure = false;

        if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) { // 不进入,当前是 match_parent -1
           //......
        }

        if (!goodMeasure) {
            childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width,
                    lp.privateFlags);
            childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height,
                    lp.privateFlags);
            if (!forRootSizeOnly || !setMeasuredRootSizeFromSpec(
                    childWidthMeasureSpec, childHeightMeasureSpec)) { // 进入
                // 开始预测量
                performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
            } else {
                // We already know how big the window should be before measuring the views.
                // We can measure the views before laying out them. This is to avoid unnecessary
                // measure.
                mViewMeasureDeferred = true;
            }
            if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
                windowSizeMayChange = true;
            }
        }

        if (DBG) {
            System.out.println("======================================");
            System.out.println("performTraversals -- after measure");
            host.debug();
        }

        return windowSizeMayChange;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

接着会调用 performMeasure 开始测量,performMeasure 使用了 MeasureSpec 的变量格式。

MeasureSpec 封装了父布局传递给子布局的布局要求,它通过一个 32 位 int 类型的值来表示,该值包含了两种信息,高两位表示的是 SpecMode(测量模式),低 30 位表示的是 SpecSize(测量的具体大小)。下面通过注释的方式来分析来类:

/**  
 * 三种SpecMode: 
 * 1.UNSPECIFIED 
 * 父 ViewGroup 没有对子View施加任何约束,子 view 可以是任意大小。这种情况比较少见,主要用于系统内部多次measure的情形,
 * 用到的一般都是可以滚动的容器中的子view,比如ListView、GridView、RecyclerView中某些情况下的子view就是这种模式。
 * 一般来说,我们不需要关注此模式。
 * 2.EXACTLY 
 * 该 view 必须使用父 ViewGroup 给其指定的尺寸。对应 match_parent 或者具体数值(比如30dp)
 * 3.AT_MOST 
 * 该 View 最大可以取父ViewGroup给其指定的尺寸。对应wrap_content
 *  
 * MeasureSpec使用了二进制去减少对象的分配。 
 */  
public class MeasureSpec {

        // 进位大小为2的30次方(int的大小为32位,所以进位30位就是要使用int的最高位和第二高位也就是32和31位做标志位)  
        private static final int MODE_SHIFT = 30;  
 
        // 运算遮罩,0x3为16进制,10进制为3,二进制为11。3向左进位30,就是11 00000000000(11后跟30个0)  
        // (遮罩的作用是用1标注需要的值,0标注不要的值。因为1与任何数做与运算都得任何数,0与任何数做与运算都得0)  
        private static final int MODE_MASK  = 0x3 << MODE_SHIFT;  
 
        // 0向左进位30,就是00 00000000000(00后跟30个0)  
        public static final int UNSPECIFIED = 0 << MODE_SHIFT;  
        // 1向左进位30,就是01 00000000000(01后跟30个0)  
        public static final int EXACTLY     = 1 << MODE_SHIFT;  
        // 2向左进位30,就是10 00000000000(10后跟30个0)  
        public static final int AT_MOST     = 2 << MODE_SHIFT;  
 
        /** 
         * 根据提供的size和mode得到一个详细的测量结果 
         */ 

        // 第一个return:
        // measureSpec = size + mode;   (注意:二进制的加法,不是十进制的加法!)  
        // 这里设计的目的就是使用一个32位的二进制数,32和31位代表了mode的值,后30位代表size的值  
        // 例如size=100(4),mode=AT_MOST,则measureSpec=100+10000...00=10000..00100  
        // 
        // 第二个return:
        // size &; ~MODE_MASK就是取size 的后30位,mode &amp; MODE_MASK就是取mode的前两位,最后执行或运算,得出来的数字,前面2位包含代表mode,后面30位代表size
        public static int makeMeasureSpec(int size, int mode) {  
            if (sUseBrokenMakeMeasureSpec) {
                return size + mode;
            } else {
                return (size & ~MODE_MASK) | (mode &  MODE_MASK);
            }
        }  
 
        /** 
         * 获得SpecMode
         */  
        // mode = measureSpec &amp; MODE_MASK;  
        // MODE_MASK = 11 00000000000(11后跟30个0),原理是用MODE_MASK后30位的0替换掉measureSpec后30位中的1,再保留32和31位的mode值。  
        // 例如10 00..00100 & 11 00..00(11后跟30个0) = 10 00..00(AT_MOST),这样就得到了mode的值  
        public static int getMode(int measureSpec) {  
            return (measureSpec & MODE_MASK);  
        }  
 
        /** 
         * 获得SpecSize 
         */  
        // size = measureSpec &  ~MODE_MASK;  
        // 原理同上,不过这次是将MODE_MASK取反,也就是变成了00 111111(00后跟30个1),将32,31替换成0也就是去掉mode,保留后30位的size  
        public static int getSize(int measureSpec) {  
            return (measureSpec &  ~MODE_MASK);  
        }  
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

了解了数据格式后,我们接着看 performMeasure 的实现:

// # ViewRootImpl

    private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
        if (mView == null) {
            return;
        }
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
        try {
            // 测量
            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
        mMeasuredWidth = mView.getMeasuredWidth();      // 结果保存在 ViewRootImpl 的 mMeasuredWidth 成员中
        mMeasuredHeight = mView.getMeasuredHeight();    // 结果保存在 ViewRootImpl 的 mMeasuredHeight 成员中
        mViewMeasureDeferred = false;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

接着看 View 的 measure 实现:

// /frameworks/base/core/java/android/view/View.java

private LongSparseLongArray mMeasureCache;

int mOldWidthMeasureSpec = Integer.MIN_VALUE;

int mOldHeightMeasureSpec = Integer.MIN_VALUE;

public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
    //首先判断当前View的layoutMode是不是特例LAYOUT_MODE_OPTICAL_BOUNDS
        boolean optical = isLayoutModeOptical(this);
        if (optical != isLayoutModeOptical(mParent)) {
          //LAYOUT_MODE_OPTICAL_BOUNDS是特例情况,比较少见,不分析
            Insets insets = getOpticalInsets();
            int oWidth  = insets.left + insets.right;
            int oHeight = insets.top  + insets.bottom;
            widthMeasureSpec  = MeasureSpec.adjust(widthMeasureSpec,  optical ? -oWidth  : oWidth);
            heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight);
        }

        //根据widthMeasureSpec和heightMeasureSpec计算key值,在下面用key值作为键,缓存我们测量得到的结果
        long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;
        //mMeasureCache是LongSparseLongArray类型的成员变量,
        //其缓存着View在不同widthMeasureSpec、heightMeasureSpec下测量过的结果
        if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2);

        //mOldWidthMeasureSpec和mOldHeightMeasureSpec分别表示上次对View进行测量时的widthMeasureSpec和heightMeasureSpec
        //执行View的measure方法时,View总是先检查一下是不是真的有必要费很大力气去做真正的测量工作
        //mPrivateFlags是一个Int类型的值,其记录了View的各种状态位
        //如果(mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT,
        //那么表示当前View需要强制进行layout(比如执行了View的forceLayout方法),所以这种情况下要尝试进行测量
        //如果新传入的widthMeasureSpec/heightMeasureSpec与上次测量时的mOldWidthMeasureSpec/mOldHeightMeasureSpec不等,
        //那么也就是说该View的父ViewGroup对该View的尺寸的限制情况有变化,这种情况下要尝试进行测量
        if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||
                widthMeasureSpec != mOldWidthMeasureSpec ||
                heightMeasureSpec != mOldHeightMeasureSpec) {

            //通过按位操作,重置View的状态标志mPrivateFlags,将其标记为未测量状态
            mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
            
            //对阿拉伯语、希伯来语等从右到左书写、布局的语言进行特殊处理
            resolveRtlPropertiesIfNeeded();

        //在View真正进行测量之前,View还想进一步确认能不能从已有的缓存mMeasureCache中读取缓存过的测量结果
        //如果是强制layout导致的测量,那么将cacheIndex设置为-1,即不从缓存中读取测量结果
        //如果不是强制layout导致的测量,那么我们就用上面根据measureSpec计算出来的key值作为缓存索引cacheIndex,这时候有可能找到相应的值,找到就返回对应索引;也可能找不到,找不到就返回-1
            int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :
                    mMeasureCache.indexOfKey(key);

            if (cacheIndex < 0 || sIgnoreMeasureCache) {
            //在缓存中找不到相应的值或者需要忽略缓存结果的时候,重新测量一次
            //此处调用onMeasure方法,并把尺寸限制条件widthMeasureSpec和heightMeasureSpec传入进去
            //onMeasure方法中将会进行实际的测量工作,并把测量的结果保存到成员变量中
                onMeasure(widthMeasureSpec, heightMeasureSpec);
            //onMeasure执行完后,通过位操作,重置View的状态mPrivateFlags,将其标记为在layout之前不必再进行测量的状态
                mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
            } else {
            //如果运行到此处,那么表示当前的条件允许View从缓存成员变量mMeasureCache中读取测量过的结果
            //用上面得到的cacheIndex从缓存mMeasureCache中取出值,不必在调用onMeasure方法进行测量了
                long value = mMeasureCache.valueAt(cacheIndex);
            //一旦我们从缓存中读到值,我们就可以调用setMeasuredDimensionRaw方法将当前测量的结果保存到成员变量中
                setMeasuredDimensionRaw((int) (value >> 32), (int) value);
                mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
            }
        //如果我们自定义的View重写了onMeasure方法,但是没有调用setMeasuredDimension()方法,
        //那么此处就会抛出异常,提醒开发者在onMeasure方法中调用setMeasuredDimension()方法
        //Android是如何知道我们有没有在onMeasure方法中调用setMeasuredDimension()方法的呢?
        //方法很简单,还是通过解析状态位mPrivateFlags。
        //setMeasuredDimension()方法中会将mPrivateFlags设置为PFLAG_MEASURED_DIMENSION_SET状态,即已测量状态,
        //此处就检查mPrivateFlags是否含有PFLAG_MEASURED_DIMENSION_SET状态即可判断setMeasuredDimension是否被调用
            if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) {
                throw new IllegalStateException("View with id " + getId() + ": "
                        + getClass().getName() + "#onMeasure() did not set the"
                        + " measured dimension by calling"
                        + " setMeasuredDimension()");
            }
        //到了这里,View已经测量完了并且将测量的结果保存在View的mMeasuredWidth和mMeasuredHeight中,将标志位置为可以layout的状态
            mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;
        }
    //mOldWidthMeasureSpec和mOldHeightMeasureSpec保存着最近一次测量时的MeasureSpec,
    //在测量完成后将这次新传入的MeasureSpec赋值给它们
        mOldWidthMeasureSpec = widthMeasureSpec;
        mOldHeightMeasureSpec = heightMeasureSpec;
    //最后用上面计算出的key作为键,测量结果作为值,将该键值对放入成员变量mMeasureCache中,
    //这样就实现了对本次测量结果的缓存,以便在下次measure方法执行的时候,有可能将其从中直接读出,
    //从而省去实际测量的步骤
        mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 |
                (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

实际的测量工作通过 onMeasure 来完成:

// /frameworks/base/core/java/android/view/View.java
// # View
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }

    protected int getSuggestedMinimumWidth() {
        return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
    }

    protected int getSuggestedMinimumHeight() {
        return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight());

    }

    public static int getDefaultSize(int size, int measureSpec) {
        int result = size;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        switch (specMode) {
        case MeasureSpec.UNSPECIFIED:
            result = size;
            break;
        case MeasureSpec.AT_MOST:
        case MeasureSpec.EXACTLY:
            result = specSize;
            break;
        }
        return result;
    }

    protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
        boolean optical = isLayoutModeOptical(this);
        if (optical != isLayoutModeOptical(mParent)) {
            Insets insets = getOpticalInsets();
            int opticalWidth  = insets.left + insets.right;
            int opticalHeight = insets.top  + insets.bottom;

            measuredWidth  += optical ? opticalWidth  : -opticalWidth;
            measuredHeight += optical ? opticalHeight : -opticalHeight;
        }
        setMeasuredDimensionRaw(measuredWidth, measuredHeight);
    }


    private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
        mMeasuredWidth = measuredWidth;
        mMeasuredHeight = measuredHeight;

        mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

对于 View 而言,主要还是靠重写 onMeasure 方法来自定义 View 测量的逻辑。

# 4. relayoutWindow 整体实现分析

在 View 树预测量完毕后,就会调用到 relayoutWindow 方法,该方法主要完成以下一些任务:

  • 添加 SurfaceControl/layer
  • 测量 Window 位置大小
  • 通过 Transaction 配置 layer 位置
  • 初始化 BLASTBufferQueue
// /frameworks/base/core/java/android/view/ViewRootImpl.java

    final W mWindow;
    final Rect mWinFrame;
    private final Rect mWinFrameInScreen = new Rect();


    private int mRelayoutSeq;
    int mLastSyncSeqId = 0;

    private final Point mSurfaceSize = new Point();


    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {

        final WindowConfiguration winConfigFromAm = getConfiguration().windowConfiguration;

        final WindowConfiguration winConfigFromWm =
                mLastReportedMergedConfiguration.getGlobalConfiguration().windowConfiguration;

        final WindowConfiguration winConfig = getCompatWindowConfiguration();

        // 预 Measure 的 View 树的尺寸信息
        final int measuredWidth = mMeasuredWidth;
        final int measuredHeight = mMeasuredHeight;
        
        final boolean relayoutAsync;
        if (LOCAL_LAYOUT
                && (mViewFrameInfo.flags & FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED) == 0
                && mWindowAttributes.type != TYPE_APPLICATION_STARTING
                && mSyncSeqId <= mLastSyncSeqId
                && winConfigFromAm.diff(winConfigFromWm, false /* compareUndefined */) == 0) { // 不进入
            // ......
        } else { // 走这里
            relayoutAsync = false;
        }


        // ......


        // 缩放调整
        final int requestedWidth = (int) (measuredWidth * appScale + 0.5f);
        final int requestedHeight = (int) (measuredHeight * appScale + 0.5f);
        int relayoutResult = 0;
        mRelayoutSeq++;

        if (relayoutAsync) {
          // .....
        } else {

            // 关注点1
            // 构建 SurfaceControl/Layer,测量窗口大小并返回,Transaction 配置 Layer
            // mTmpFrames 会返回 wms 布局后的尺寸信息
            // mSurfaceControl 返回新构建的 SurfaceControl
            relayoutResult = mWindowSession.relayout(mWindow, params,
                    requestedWidth, requestedHeight, viewVisibility,
                    insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
                    mLastSyncSeqId, mTmpFrames, mPendingMergedConfiguration, mSurfaceControl,
                    mTempInsets, mTempControls, mRelayoutBundle);

           mWinFrameInScreen.set(mTmpFrames.frame);
           // ......
        }

        final int transformHint = SurfaceControl.rotationToBufferTransform(
                (mDisplay.getInstallOrientation() + mDisplay.getRotation()) % 4);

        // 计算 Surface 的宽高
        // 结果保存在 mSurfaceSize
        WindowLayout.computeSurfaceSize(mWindowAttributes, winConfig.getMaxBounds(), requestedWidth,
                requestedHeight, mWinFrameInScreen, mPendingDragResizing, mSurfaceSize);

        final boolean transformHintChanged = transformHint != mLastTransformHint;
        final boolean sizeChanged = !mLastSurfaceSize.equals(mSurfaceSize);
        final boolean surfaceControlChanged =
                (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED) == RELAYOUT_RES_SURFACE_CHANGED;
        if (mAttachInfo.mThreadedRenderer != null &&
                (transformHintChanged || sizeChanged || surfaceControlChanged)) {
            if (mAttachInfo.mThreadedRenderer.pause()) {
                // Animations were running so we need to push a frame
                // to resume them
                mDirty.set(0, 0, mWidth, mHeight);
            }
        }

        if (mSurfaceControl.isValid() && !HardwareRenderer.isDrawingEnabled()) {
            // When drawing is disabled the window layer won't have a valid buffer.
            // Set a window crop so input can get delivered to the window.
            mTransaction.setWindowCrop(mSurfaceControl, mSurfaceSize.x, mSurfaceSize.y).apply();
        }

        mLastTransformHint = transformHint;

        mSurfaceControl.setTransformHint(transformHint);

        if (mAttachInfo.mContentCaptureManager != null) {
            MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
                    .getMainContentCaptureSession();
            mainSession.notifyWindowBoundsChanged(mainSession.getId(),
                    getConfiguration().windowConfiguration.getBounds());
        }

        if (mSurfaceControl.isValid()) {
            if (!useBLAST()) {
                mSurface.copyFrom(mSurfaceControl);
            } else {
                // 关注点2
                updateBlastSurfaceIfNeeded();
            }
            if (mAttachInfo.mThreadedRenderer != null) {
                mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue);
            }
            updateRenderHdrSdrRatio();
            if (mPreviousTransformHint != transformHint) {
                mPreviousTransformHint = transformHint;
                dispatchTransformHintChanged(transformHint);
            }
        } else {
            if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.pause()) {
                mDirty.set(0, 0, mWidth, mHeight);
            }
            destroySurface();
        }

        if (restore) {
            params.restore();
        }

        // 关注点 3
        setFrame(mTmpFrames.frame, true /* withinRelayout */);
        return relayoutResult;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

要点:

  • WindowSession.relayout,构建 SurfaceControl/Layer,计算尺寸,向 sf 提交 Transaction 事务,计算出的尺寸存到 outFrames 中返回给 App
  • updateBlastSurfaceIfNeeded,构建 bbq
  • setFrame,将计算出的尺寸信息保存到 ViewRootImpl 成员变量 mWinFrame 中

# 4.1 WindowSession.relayout 实现分析

WindowSession.relayout 会远程调用到 WMS 中:

// /frameworks/base/services/core/java/com/android/server/wm/Session.java

    final WindowManagerService mService;

    @Override
    public int relayout(IWindow window, WindowManager.LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
            int lastSyncSeqId, ClientWindowFrames outFrames,
            MergedConfiguration mergedConfiguration, SurfaceControl outSurfaceControl,
            InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls,
            Bundle outSyncSeqIdBundle) {
        if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
                + Binder.getCallingPid());
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
        int res = mService.relayoutWindow(this, window, attrs,
                requestedWidth, requestedHeight, viewFlags, flags, seq,
                lastSyncSeqId, outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
                outActiveControls, outSyncSeqIdBundle);
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
                + Binder.getCallingPid());
        return res;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

接着调用到 wms 的 relayoutWindow 方法:

// # WindowManagerService

    // requestedWidth requestedHeight 来自预 measure
    public int relayoutWindow(Session session, IWindow client, LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewVisibility, int flags, int seq,
            int lastSyncSeqId, ClientWindowFrames outFrames,
            MergedConfiguration outMergedConfiguration, SurfaceControl outSurfaceControl,
            InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls,
            Bundle outSyncIdBundle) {
         // ......
         synchronized (mGlobalLock) {
            // 从 mWindowMap 中获取 WindowState
            // WindowState 已在阶段二中初始化
            final WindowState win = windowForClientLocked(session, client, false);
            if (win == null) {
                return 0;
            }
            // ......

            // 拿到当前屏幕对应的节点
            final DisplayContent displayContent = win.getDisplayContent();
            final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
            
            if (viewVisibility != View.GONE) {
               // 把应用端请求的大小,保存到 WindowState 下
               win.setRequestedSize(requestedWidth, requestedHeight);
            }

            // ......
            if (attrs != null) {
               // 调整窗口属性和类型
               displayPolicy.adjustWindowParamsLw(win, attrs);
               //......
            }
            // .......
            // 设置窗口可见 viewVisibility = VISIBLE
            win.setViewVisibility(viewVisibility);

            // 打印Proto日志
            ProtoLog.i(WM_DEBUG_SCREEN_ON,
                    "Relayout %s: oldVis=%d newVis=%d. %s", win, oldVisibility,
                            viewVisibility, new RuntimeException().fillInStackTrace());
            // ......
            if (shouldRelayout && outSurfaceControl != null) {
                try {
                    // 关注点1, 创建SurfaceControl
                    result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
                } catch (Exception e) {
                    ......
                    return 0;
                }
            }

            // 关注点2 计算窗口大小 
            mWindowPlacerLocked.performSurfacePlacement(true /* force */);
            // ......
            if (focusMayChange) {
                // 更新焦点
                if (updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/)) {
                    imMayMove = false;
                }
            }
            // ......
            // 关注点3 填充 WMS 计算好后的数据,返回应用端
            win.fillClientWindowFramesAndConfiguration(outFrames, outMergedConfiguration,
                    false /* useLatestConfig */, shouldRelayout);
            // ......
         }

         Binder.restoreCallingIdentity(origId);
         return result;
      }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

主要关注以下三点:

  • 关注点1,创建 SurfaceControl
  • 关注点2 计算窗口大小
  • 关注点3 填充 WMS 计算好后的数据,返回应用端

# 4.1.1 SurfaceControl 的构建过程

先给出一个 SurfaceControl 的构建过程中相关类类图:

20241031223135

我们再接着看代码,createSurfaceControl 实现如下:

// # WindowManagerService

   // todo outSurfaceControl 参数如何从 App 传到 SystemServer,SystemServer 如何传回 App。
   private int createSurfaceControl(SurfaceControl outSurfaceControl, int result,
      WindowState win, WindowStateAnimator winAnimator) {
      
      if (!win.mHasSurface) {
            result |= RELAYOUT_RES_SURFACE_CHANGED;
      }

      // 1. 创建 WindowSurfaceController 对象
      WindowSurfaceController surfaceController;
      try {
         // 2. 创建 “Buff” 类型 Surface
         // WindowState 挂载到窗口容器树时,创建了一个容器类型的 Surface
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl");
         surfaceController = winAnimator.createSurfaceLocked();
      } finally {
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
      }
      if (surfaceController != null) {
         // 3. 出参给应用端
         surfaceController.getSurfaceControl(outSurfaceControl);
         // 打印日志,outSurfaceControl 复制到了  framework 的值
         ProtoLog.i(WM_SHOW_TRANSACTIONS, "OUT SURFACE %s: copied", outSurfaceControl);

      } else {
            // For some reason there isn't a surface.  Clear the
            // caller's object so they see the same state.
            ProtoLog.w(WM_ERROR, "Failed to create surface control for %s", win);
            outSurfaceControl.release();
      }

      return result;
   }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

继续调用到 WinStateAnimator 的 createSurfaceLocked 方法:

// # WindowStateAnimator

   WindowSurfaceController mSurfaceController;
   // WindowState的状态
   int mDrawState;

   WindowSurfaceController createSurfaceLocked() {
      
      final WindowState w = mWin;
      
      if (mSurfaceController != null) {
            return mSurfaceController;
      }

      w.setHasSurface(false);
      // 打印窗口状态
      ProtoLog.i(WM_DEBUG_ANIM, "createSurface %s: mDrawState=DRAW_PENDING", this);
      // 重点* 1. 重置窗口状态  -- DRAW_PENDING
      resetDrawState();
      // ......
      // 重点* 2. 创建 WindowSurfaceController
      mSurfaceController = new WindowSurfaceController(attrs.getTitle().toString(), format,
                    flags, this, attrs.type);
      // ......
      return mSurfaceController;
   }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

resetDrawState 实现如下:

# WindowStateAnimator

   void resetDrawState() {
      // 设置 windowState 状态为 DRAW_PENDING
      mDrawState = DRAW_PENDING;

      if (mWin.mActivityRecord == null) {
         return;
      }

      if (!mWin.mActivityRecord.isAnimating(TRANSITION)) {
         mWin.mActivityRecord.clearAllDrawn();
      }
   }
1
2
3
4
5
6
7
8
9
10
11
12
13
14

WindowSurfaceController 构造方法:

//# WindowSurfaceController

   SurfaceControl mSurfaceControl;

   WindowSurfaceController(String name, int format, int flags, WindowStateAnimator animator,
            int windowType) {
      mAnimator = animator;
      // 1. 也会作为 Surface 的 name
      title = name;

      mService = animator.mService;
      // 2. 拿到 WindowState
      final WindowState win = animator.mWin;
      mWindowType = windowType;
      mWindowSession = win.mSession;

      Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "new SurfaceControl");
      // 3. 重点* 构建Surface(也是通过makeSurface 方法)
      final SurfaceControl.Builder b = win.makeSurface()
               .setParent(win.getSurfaceControl()) // 设置为父节点,WindowState 挂载的时候就有一个 SurfaceControl 了
               .setName(name) //设置name
               .setFormat(format)
               .setFlags(flags)
               .setMetadata(METADATA_WINDOW_TYPE, windowType)
               .setMetadata(METADATA_OWNER_UID, mWindowSession.mUid)
               .setMetadata(METADATA_OWNER_PID, mWindowSession.mPid)
               .setCallsite("WindowSurfaceController");

      final boolean useBLAST = mService.mUseBLAST && ((win.getAttrs().privateFlags
               & WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST) != 0);
      // 高版本都为BLAST
      if (useBLAST) {
         // 4. 重点* 设置为“Buff”图层
         b.setBLASTLayer();
      }
      // 触发build
      mSurfaceControl = b.build();
      Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

build 的实现如下:

        public SurfaceControl build() {
            if (mWidth < 0 || mHeight < 0) {
                throw new IllegalStateException(
                        "width and height must be positive or unset");
            }
            if ((mWidth > 0 || mHeight > 0) && (isEffectLayer() || isContainerLayer())) {
                throw new IllegalStateException(
                        "Only buffer layers can set a valid buffer size.");
            }

            if (mName == null) {
                Log.w(TAG, "Missing name for SurfaceControl", new Throwable());
            }

            if ((mFlags & FX_SURFACE_MASK) == FX_SURFACE_NORMAL) {
                setBLASTLayer();
            }

            return new SurfaceControl(
                    mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata,
                    mLocalOwnerView, mCallsite);
        }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
            SurfaceControl parent, SparseIntArray metadata, WeakReference<View> localOwnerView,
            String callsite)
                    throws OutOfResourcesException, IllegalArgumentException {
        if (name == null) {
            throw new IllegalArgumentException("name must not be null");
        }

        mName = name;
        mWidth = w;
        mHeight = h;
        mLocalOwnerView = localOwnerView;
        Parcel metaParcel = Parcel.obtain();
        long nativeObject = 0;
        try {
            if (metadata != null && metadata.size() > 0) {
                metaParcel.writeInt(metadata.size());
                for (int i = 0; i < metadata.size(); ++i) {
                    metaParcel.writeInt(metadata.keyAt(i));
                    metaParcel.writeByteArray(
                            ByteBuffer.allocate(4).order(ByteOrder.nativeOrder())
                                    .putInt(metadata.valueAt(i)).array());
                }
                metaParcel.setDataPosition(0);
            }
            nativeObject = nativeCreate(session, name, w, h, format, flags,
                    parent != null ? parent.mNativeObject : 0, metaParcel);
        } finally {
            metaParcel.recycle();
        }
        if (nativeObject == 0) {
            throw new OutOfResourcesException(
                    "Couldn't allocate SurfaceControl native object");
        }
        assignNativeObject(nativeObject, callsite);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    private void assignNativeObject(long nativeObject, String callsite) {
        if (mNativeObject != 0) {
            release();
        }
        if (nativeObject != 0) {
            mFreeNativeResources =
                    sRegistry.registerNativeAllocation(this, nativeObject);
        }
        mNativeObject = nativeObject;
        mNativeHandle = mNativeObject != 0 ? nativeGetHandle(nativeObject) : 0;
        if (sDebugUsageAfterRelease && mNativeObject == 0) {
            mReleaseStack = new Throwable("Assigned invalid nativeObject");
        } else {
            mReleaseStack = null;
        }
        setUnreleasedWarningCallSite(callsite);
        if (nativeObject != 0) {
            // Only add valid surface controls to the registry. This is called at the end of this
            // method since its information is dumped if the process threshold is reached.
            addToRegistry();
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

进入到 jni 层:

// /frameworks/base/core/jni/android_view_SurfaceControl.cpp
static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,F
        jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
        jobject metadataParcel) {
    ScopedUtfChars name(env, nameStr);
    sp<SurfaceComposerClient> client;
    if (sessionObj != NULL) {
        client = android_view_SurfaceSession_getClient(env, sessionObj);
    } else {
        client = SurfaceComposerClient::getDefault();
    }
    SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
    sp<SurfaceControl> surface;
    LayerMetadata metadata;
    Parcel* parcel = parcelForJavaObject(env, metadataParcel);
    if (parcel && !parcel->objectsCount()) {
        status_t err = metadata.readFromParcel(parcel);
        if (err != NO_ERROR) {
          jniThrowException(env, "java/lang/IllegalArgumentException",
                            "Metadata parcel has wrong format");
        }
    }

    sp<IBinder> parentHandle;
    if (parent != nullptr) {
        parentHandle = parent->getHandle();
    }
    
    // 远程调用 sf
    // sf 那边会创建 Layer
    // 返回 SurfaceControl,其中有一个重要成员 mHandle,用于索引 Layer
    status_t err = client->createSurfaceChecked(String8(name.c_str()), w, h, format, &surface,
                                                flags, parentHandle, std::move(metadata));
    if (err == NAME_NOT_FOUND) {
        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
        return 0;
    } else if (err != NO_ERROR) {
        jniThrowException(env, OutOfResourcesException, statusToString(err).c_str());
        return 0;
    }

    surface->incStrong((void *)nativeCreate);
    return reinterpret_cast<jlong>(surface.get());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

创建好了 SurfaceControl,

// todo createSurfaceChecked 的分析

# 4.1.2 计算布局窗口

performSurfacePlacement

WMS 中最核心的方法,负责所有窗口的 Surface 的摆放工作,如何显示、显示在什么位置、显示区域多大,都将通过这个方法,完成确认并下发给 SurfaceFlinger 中进行显示。当 WMS 中任何状态发生变化,都会触发该方法的执行,对整个 WMS 树结构进行遍历,确定所有的 Surface 的可见与否。

// # WindowSurfacePlacer

    // 控制是否需要继续执行 performSurfacePlacementLoop 方法
    private boolean mTraversalScheduled;
    // 延迟 layout 就会 +1
    private int mDeferDepth = 0;

    final void performSurfacePlacement(boolean force) { // true
        if (mDeferDepth > 0 && !force) {
            mDeferredRequests++;
            return;
        }
        // 最大次数循环为6次
        int loopCount = 6;
        do {
            // 设置为false
            mTraversalScheduled = false;
            // 重点方法
            performSurfacePlacementLoop();
            // 移除Handler的处理
            mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
            loopCount--;
        // 结束条件为 mTraversalScheduled 不为false 和 loopCount大于0 ,也就最多6次
        } while ( mTraversalScheduled && loopCount > 0);
        mService.mRoot.mWallpaperActionPending = false;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

为什么是 6 次?

# WindowSurfacePlacer

    private void performSurfacePlacementLoop() {

        // ......
        // 重点*1. 对所有窗口执行布局操作
        mService.mRoot.performSurfacePlacement();
        // 布局完成
        mInLayout = false;
        // 若需要布局,(Root检查每个DC是否需要)
        if (mService.mRoot.isLayoutNeeded()) {
            if (++mLayoutRepeatCount < 6) {
                requestTraversal();
            } else {
                Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
                mLayoutRepeatCount = 0;
            }
        } else {
            mLayoutRepeatCount = 0;
        }   
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# RootWindowContainer

    // 这个方法加上了trace
    void performSurfacePlacement() {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");
        try {
            performSurfacePlacementNoTrace();
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }


    // 主要干活的还是这个
    void performSurfacePlacementNoTrace() {
        // ......
        // 1. 如果需要,则更新焦点
        if (mWmService.mFocusMayChange) {
            mWmService.mFocusMayChange = false;
            mWmService.updateFocusedWindowLocked(
                    UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
        }
        // ......
        // Trace
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
        // 开启事务
        // 计算号尺寸信息,然后通过 Transaction 提交给 sf。
        mWmService.openSurfaceTransaction();
        try {
            // 2.. 处理事务(执行窗口尺寸计算,surface状态变更等操作)
            applySurfaceChangesTransaction();
        } catch (RuntimeException e) {
            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
        } finally {
            // 关闭事务,做事务提交
            mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
        ......
        // 3. Activity 切换事务处理,
        // 条件满足也会将窗口状态设置为HAS_DRAW 流程
        checkAppTransitionReady(surfacePlacer);
        ......
        // 再次判断是否需要处理焦点变化
        if (mWmService.mFocusMayChange) {
            mWmService.mFocusMayChange = false;
            mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
                    false /*updateInputWindows*/);
        }
        ......
        // 4. 如果过程中size或者位置变化,则通知客户端重新relayout
        handleResizingWindows();
        ......
        // 5. 销毁不可见的窗口
        i = mWmService.mDestroySurface.size();
        if (i > 0) {
            do {
                i--;
                WindowState win = mWmService.mDestroySurface.get(i);
                win.mDestroying = false;
                final DisplayContent displayContent = win.getDisplayContent();
                if (displayContent.mInputMethodWindow == win) {
                    displayContent.setInputMethodWindowLocked(null);
                }
                if (displayContent.mWallpaperController.isWallpaperTarget(win)) {
                    displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                }
                win.destroySurfaceUnchecked();
            } while (i > 0);
            mWmService.mDestroySurface.clear();
        }
        ......
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

几个关注的点:

  • mWmService.openSurfaceTransaction() 开启事务
  • applySurfaceChangesTransaction() 处理事务
  • mWmService.closeSurfaceTransaction,apply 事务

开启事务

// /frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
    void openSurfaceTransaction() {
        try {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "openSurfaceTransaction");
            SurfaceControl.openTransaction();
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }
1
2
3
4
5
6
7
8
9
// /frameworks/base/core/java/android/view/SurfaceControl.java
// # SurfaceControl

    static GlobalTransactionWrapper sGlobalTransaction;

    @UnsupportedAppUsage
    public static void openTransaction() {
        synchronized (SurfaceControl.class) {
            if (sGlobalTransaction == null) {
                sGlobalTransaction = new GlobalTransactionWrapper();
            }
            synchronized(SurfaceControl.class) {
                sTransactionNestCount++;
            }
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// /frameworks/base/core/java/android/view/SurfaceControl.java
// SurfaceControl 的内部类 GlobalTransactionWrapper

    private static class GlobalTransactionWrapper extends SurfaceControl.Transaction {

        void applyGlobalTransaction(boolean sync) {
            applyResizedSurfaces();
            notifyReparentedSurfaces();
            nativeApplyTransaction(mNativeObject, sync);
        }

        @Override
        public void apply(boolean sync) {
            throw new RuntimeException("Global transaction must be applied from closeTransaction");
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

父类 SurfaceControl.Transaction

    public static class Transaction implements Closeable, Parcelable {

        public long mNativeObject;
        
        public Transaction() {
            this(nativeCreateTransaction());
        }

        private Transaction(long nativeObject) {
            mNativeObject = nativeObject;
            mFreeNativeResources =
                    sRegistry.registerNativeAllocation(this, mNativeObject);
        }

    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// /frameworks/base/core/jni/android_view_SurfaceControl.cpp
static jlong nativeCreateTransaction(JNIEnv* env, jclass clazz) {
    return reinterpret_cast<jlong>(new SurfaceComposerClient::Transaction);
}
1
2
3
4

处理事务:

// # RootWindowContainer
    private void applySurfaceChangesTransaction() {
        // TODO(multi-display): Support these features on secondary screens.
        final DisplayContent defaultDc = mDefaultDisplay;
        final DisplayInfo defaultInfo = defaultDc.getDisplayInfo();
        final int defaultDw = defaultInfo.logicalWidth;
        final int defaultDh = defaultInfo.logicalHeight;
        
        final SurfaceControl.Transaction t = defaultDc.getSyncTransaction();

        if (mWmService.mWatermark != null) {
            mWmService.mWatermark.positionSurface(defaultDw, defaultDh, t);
        }
        if (mWmService.mStrictModeFlash != null) {
            mWmService.mStrictModeFlash.positionSurface(defaultDw, defaultDh, t);
        }
        if (mWmService.mEmulatorDisplayOverlay != null) {
            mWmService.mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh,
                    defaultDc.getRotation(), t);
        }

        // 遍历子节点 DisplayContent,也就是每一个屏幕,通常只有一个屏幕
        final int count = mChildren.size();
        for (int j = 0; j < count; ++j) {
            final DisplayContent dc = mChildren.get(j);
            dc.applySurfaceChangesTransaction();
        }

        // todo DisplayManager 系统服务 ???
        // Give the display manager a chance to adjust properties like display rotation if it needs
        // to.
        mWmService.mDisplayManagerInternal.performTraversal(t);
        if (t != defaultDc.mSyncTransaction) {
            SurfaceControl.mergeToGlobalTransaction(t);
        }
    }    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// # DisplayContent    
   
    private final LinkedList<ActivityRecord> mTmpUpdateAllDrawn = new LinkedList();
   
    void applySurfaceChangesTransaction() {

        final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;

        beginHoldScreenUpdate();

        mTmpUpdateAllDrawn.clear();

        if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("On entry to LockedInner",
                pendingLayoutChanges);

        if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
            mWallpaperController.adjustWallpaperWindows();
        }

        if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
            if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
            if (updateOrientation()) {
                setLayoutNeeded();
                sendNewConfiguration();
            }
        }

        if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
            setLayoutNeeded();
        }

        // 关注点1,布局
        // 各个WindowState的WindowFrame由此步进行确认
        // Perform a layout, if needed.
        performLayout(true /* initial */, false /* updateInputWindows */);
        pendingLayoutChanges = 0;

        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyPostLayoutPolicy");
        try {
            // 主要是一些系统窗口相关的处理,暂时不管
            // 进行 Display policy 和 Window policy 的应用对各个 WindowState 应用当前的一些策略,并策略用于控制窗口的显示和隐藏状态中去。
            mDisplayPolicy.beginPostLayoutPolicyLw();
            forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
            mDisplayPolicy.finishPostLayoutPolicyLw();
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
        mInsetsStateController.onPostLayout();

        mTmpApplySurfaceChangesTransactionState.reset();

        // 关注点2
        // 遍历各个 WindowState,根据携带参数确定是否修改逻辑屏显示参数、对 WindowState 状态进行由 COMMIT_DRAW_PENDING 到 READY_TO_SHOW 的转变;
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyWindowSurfaceChanges");
        try {
            forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }

        // 关注点3
        // 对每个 Surface 的位置、大小等做最后的准备,并提交给 sGlobalTransation 对象等待进行 show 或 hide。
        prepareSurfaces();

        // This should be called after the insets have been dispatched to clients and we have
        // committed finish drawing windows.
        mInsetsStateController.getImeSourceProvider().checkShowImePostLayout();

        mLastHasContent = mTmpApplySurfaceChangesTransactionState.displayHasContent;
        if (!inTransition() && !mDisplayRotation.isRotatingSeamlessly()) {
            mWmService.mDisplayManagerInternal.setDisplayProperties(mDisplayId,
                    mLastHasContent,
                    mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,
                    mTmpApplySurfaceChangesTransactionState.preferredModeId,
                    mTmpApplySurfaceChangesTransactionState.preferredMinRefreshRate,
                    mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate,
                    mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
                    mTmpApplySurfaceChangesTransactionState.disableHdrConversion,
                    true /* inTraversal, must call performTraversalInTrans... below */);
        }
        // If the display now has content, or no longer has content, update recording.
        updateRecording();

        final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible();
        if (wallpaperVisible != mLastWallpaperVisible) {
            mLastWallpaperVisible = wallpaperVisible;
            mWmService.mWallpaperVisibilityListeners.notifyWallpaperVisibilityChanged(this);
        }

        while (!mTmpUpdateAllDrawn.isEmpty()) {
            final ActivityRecord activity = mTmpUpdateAllDrawn.removeLast();
            // See if any windows have been drawn, so they (and others associated with them)
            // can now be shown.
            activity.updateAllDrawn();
        }

        finishHoldScreenUpdate();
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  • 关注点1,performLayout,确定每个 WindowState 的尺寸信息
  • 关注点2,mApplySurfaceChangesTransaction
  • 关注点3,prepareSurfaces()
// # DisplayContent

    // 标记是否需要执行layout
    private boolean mLayoutNeeded;

    boolean isLayoutNeeded() {
        return mLayoutNeeded;
    }

    // 根据前面流程,如果为false则表示不会执行循环
    private void clearLayoutNeeded() {
        if (DEBUG_LAYOUT) Slog.w(TAG_WM, "clearLayoutNeeded: callers=" + Debug.getCallers(3));
        mLayoutNeeded = false;
    }
    
    void performLayout(boolean initial, boolean updateInputWindows) {
        // 加上trace
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performLayout");
        try {
            performLayoutNoTrace(initial, updateInputWindows);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }

    // 主要方法
    private void performLayoutNoTrace(boolean initial, boolean updateInputWindows) {
        // 判断是否需要布局,不需要则直接返回,内部是通过 mLayoutNeeded 判断
        if (!isLayoutNeeded()) {
            return;
        }
        // 将 mLayoutNeeded 设置为 flase
        clearLayoutNeeded();
        //......
        // 重点* 1. 对所有顶级窗口进行布局
        forAllWindows(mPerformLayout, true /* traverseTopToBottom */);

        // 重点* 2. 处理子窗口的布局
        forAllWindows(mPerformLayoutAttached, true /* traverseTopToBottom */);
        //......
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// # DisplayContent

    DisplayFrames mDisplayFrames;

    private final Consumer<WindowState> mPerformLayout = w -> {
        // 如果当前窗口为子窗口则直接返回
        if (w.mLayoutAttached) {
            return;
        }

        // 先判断当前窗口是否会不可见
        final boolean gone = w.isGoneForLayout();
        // 如果窗口不是不可见的,或者窗口没有框架,或者窗口需要布局
        if (!gone || !w.mHaveFrame || w.mLayoutNeeded) {
            ......
            // 重点*1. 调用 DisplayPolicy::layoutWindowLw
            getDisplayPolicy().layoutWindowLw(w, null, mDisplayFrames);
            ......
            if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame=" + w.getFrame()
                    + " mParentFrame=" + w.getParentFrame()
                    + " mDisplayFrame=" + w.getDisplayFrame());
        }
    };

    private final Consumer<WindowState> mPerformLayoutAttached = w -> {
        // 如果不是子窗口则返回
        if (!w.mLayoutAttached) {
            return;
        }

        if ((w.mViewVisibility != GONE && w.mRelayoutCalled) || !w.mHaveFrame
                || w.mLayoutNeeded) {
            ......
            getDisplayPolicy().layoutWindowLw(w, w.getParentWindow(), mDisplayFrames);
            w.mLayoutSeq = mLayoutSeq;
            if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrame()
                    + " mParentFrame=" + w.getParentFrame()
                    + " mDisplayFrame=" + w.getDisplayFrame());
        }
    };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

当 WindowState 可见时,执行 DisplayPolicy#layoutWindowLw() 方法

这里将会根据 DisplayFrame 对象,对 WindowFrame 中的各个 Rect 对象属性进行确定

# DisplayPolicy

    public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
        
        // 判断是否需要跳过布局
        if (win.skipLayout()) {
            return;
        }

        // 获取DisplayFrames
        displayFrames = win.getDisplayFrames(displayFrames);
        // 获取某个方向的窗口布局参数
        final WindowManager.LayoutParams attrs = win.getLayoutingAttrs(displayFrames.mRotation);
        final Rect attachedWindowFrame = attached != null ? attached.getFrame() : null;

        // If this window has different LayoutParams for rotations, we cannot trust its requested
        // size. Because it might have not sent its requested size for the new rotation.
        final boolean trustedSize = attrs == win.mAttrs;
        // 预 Measure 计算出的 View 树的尺寸信息
        // 和预测量的差异主要是这两个参数
        final int requestedWidth = trustedSize ? win.mRequestedWidth : UNSPECIFIED_LENGTH;
        final int requestedHeight = trustedSize ? win.mRequestedHeight : UNSPECIFIED_LENGTH;
        // 重点* 1. 调用 WindowLayout.computeFrames 计算窗口布局大小
        mWindowLayout.computeFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe,
                win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight,
                win.getRequestedVisibleTypes(), win.mGlobalScale, sTmpClientFrames);
        // 重点* 2. 将计算的布局参数赋值给 windowFrames
        // 如果要修改窗口尺寸,就在这里动手脚
        win.setFrames(sTmpClientFrames, win.mRequestedWidth, win.mRequestedHeight);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

启动过程,打断点看一下尺寸信息。

20241212222002

20241212222124

全是满尺寸,看不太出来什么差异。

添加悬浮窗,看下尺寸信息

20241212222405

20241212222714

// 搞个悬浮窗子窗口看看 ?

public class ClientWindowFrames implements Parcelable {

    /** The actual window bounds. */
    public final @NonNull Rect frame = new Rect();

    /**
     * The container frame that is usually the same as display size. It may exclude the area of
     * insets if the window layout parameter has specified fit-insets-sides.
     */
    public final @NonNull Rect displayFrame = new Rect();

    /**
     * The frame to be referenced while applying gravity and MATCH_PARENT.
     */
    public final @NonNull Rect parentFrame = new Rect();

    /**
     * The frame this window attaches to. If this is not null, this is the frame of the parent
     * window.
     */
    public @Nullable Rect attachedFrame;

    // ......
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# WindowLayout

    //参数:
    // attrs: 窗口参数
    // state: Insets状态
    // displayCutoutSafe: 剪裁区域
    // windowBounds: 窗口的边界,对于 Activity 就是屏幕大小
    // windowingMode: 窗口模式
    // requestedWidth,requestedHeight: 请求的宽高
    // requestedVisibleTypes: 请求显示的内边距类型
    // compatScale:兼容性缩放因子
    // frames : 输出的窗口位置信息
    
    public void computeFrames(WindowManager.LayoutParams attrs, InsetsState state,
            Rect displayCutoutSafe, Rect windowBounds, @WindowingMode int windowingMode,
            int requestedWidth, int requestedHeight, @InsetsType int requestedVisibleTypes,
            float compatScale, ClientWindowFrames frames) {
        // 获取窗口的类型、标志和私有标志,以便后面的计算使用
        final int type = attrs.type;
        final int fl = attrs.flags;
        final int pfl = attrs.privateFlags;
        // 判断窗口是否指定了 FLAG_LAYOUT_IN_SCREEN 标志,该标志表示窗口是否应该扩展到屏幕的尺寸
        final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
        // 获取输出的各个位置信息,包括显示区域、父窗口区域和窗口区域
        final Rect attachedWindowFrame = frames.attachedFrame;
        final Rect outDisplayFrame = frames.displayFrame;
        final Rect outParentFrame = frames.parentFrame;
        final Rect outFrame = frames.frame;
        

        // 1. 计算 outDisplayFrame
        // 通过 InsetsState 计算窗口的 Insets 值。
        // Compute bounds restricted by insets
        final Insets insets = state.calculateInsets(windowBounds, attrs.getFitInsetsTypes(),
                attrs.isFitInsetsIgnoringVisibility());
        // 获取窗口在各个方向上是否需要计算 Insets 值,然后根据这些方向计算出对应方向的 Insets 值
        final @WindowInsets.Side.InsetsSide int sides = attrs.getFitInsetsSides();
        final int left = (sides & WindowInsets.Side.LEFT) != 0 ? insets.left : 0;
        final int top = (sides & WindowInsets.Side.TOP) != 0 ? insets.top : 0;
        final int right = (sides & WindowInsets.Side.RIGHT) != 0 ? insets.right : 0;
        final int bottom = (sides & WindowInsets.Side.BOTTOM) != 0 ? insets.bottom : 0;
        // 将显示区域的边界计算出来,它是应用窗口在整个屏幕上的可见区域。其中,
        //windowBounds表示应用窗口的位置和大小,left、top、right和bottom表示计算得到的窗口与屏幕边界的间距。
        outDisplayFrame.set(windowBounds.left + left, windowBounds.top + top,
                windowBounds.right - right, windowBounds.bottom - bottom);


        // 2. 计算 outParentFrame
        // 计算出应用窗口父容器的边界
        if (attachedWindowFrame == null) {
            // 如果应用窗口未附加到其他窗口上,则父容器边界与显示区域相同。
            outParentFrame.set(outDisplayFrame);
            if ((pfl & PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME) != 0) {
                final InsetsSource source = state.peekSource(ID_IME);
                if (source != null) {
                    outParentFrame.inset(source.calculateInsets(
                            outParentFrame, false /* ignoreVisibility */));
                }
            }
        } else {
            // 如果应用窗口附加到其他窗口上,则父容器边界要根据应用窗口所附加的窗口的位置和大小进行调整
            outParentFrame.set(!layoutInScreen ? attachedWindowFrame : outDisplayFrame);
        }



        //计算出在显示区域中可能被切割的区域,即如果屏幕上有凸起的部分(如前置摄像头等)则需要将此部分从显示区域中去除
        // Compute bounds restricted by display cutout
        // 其中,cutoutMode 表示窗口如何处理屏幕凸起部分
        final int cutoutMode = attrs.layoutInDisplayCutoutMode;
        // cutout表示屏幕凸起部分的信息
        final DisplayCutout cutout = state.getDisplayCutout();
        // displayCutoutSafe表示在应用窗口可见区域中,不会被凸起部分遮挡的区域
        final Rect displayCutoutSafeExceptMaybeBars = mTempDisplayCutoutSafeExceptMaybeBarsRect;
        displayCutoutSafeExceptMaybeBars.set(displayCutoutSafe);
        frames.isParentFrameClippedByDisplayCutout = false;
        // 处理窗口与显示屏中的刘海屏幕(也称为"切口")之间的关系,以确保窗口不会被刘海屏幕覆盖
        // 在Android系统中,刘海屏幕的信息由DisplayCutout类来表示,而这个类的实例通常可以从InsetsState对象中获取
        if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS && !cutout.isEmpty()) {
            // Ensure that windows with a non-ALWAYS display cutout mode are laid out in
            // the cutout safe zone.
            final Rect displayFrame = state.getDisplayFrame();
            if (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) {
                if (displayFrame.width() < displayFrame.height()) {
                    displayCutoutSafeExceptMaybeBars.top = MIN_Y;
                    displayCutoutSafeExceptMaybeBars.bottom = MAX_Y;
                } else {
                    displayCutoutSafeExceptMaybeBars.left = MIN_X;
                    displayCutoutSafeExceptMaybeBars.right = MAX_X;
                }
            }
            final boolean layoutInsetDecor = (attrs.flags & FLAG_LAYOUT_INSET_DECOR) != 0;
            if (layoutInScreen && layoutInsetDecor
                    && (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
                    || cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES)) {
                final Insets systemBarsInsets = state.calculateInsets(
                        displayFrame, systemBars(), requestedVisibleTypes);
                if (systemBarsInsets.left > 0) {
                    displayCutoutSafeExceptMaybeBars.left = MIN_X;
                }
                if (systemBarsInsets.top > 0) {
                    displayCutoutSafeExceptMaybeBars.top = MIN_Y;
                }
                if (systemBarsInsets.right > 0) {
                    displayCutoutSafeExceptMaybeBars.right = MAX_X;
                }
                if (systemBarsInsets.bottom > 0) {
                    displayCutoutSafeExceptMaybeBars.bottom = MAX_Y;
                }
            }
            // 刘海屏处理结束
            // 处理输入法类型窗口
            if (type == TYPE_INPUT_METHOD
                    && displayCutoutSafeExceptMaybeBars.bottom != MAX_Y
                    && state.calculateInsets(displayFrame, navigationBars(), true).bottom > 0) {
                // 这是为了确保输入法窗口不会被底部切口遮挡,同时又能够利用底部空间。
                // The IME can always extend under the bottom cutout if the navbar is there.
                displayCutoutSafeExceptMaybeBars.bottom = MAX_Y;
            }
            // 用 attachedWindowFrame 和 layoutInScreen 两个变量判断窗口是否连接到了父级并且没有被放置在屏幕之外
            // 即窗口在父级内进行了布局
            // 如果两个条件都满足,说明窗口没有超出父级边界,不需要被剪裁,因此不需要处理刘海屏幕问题
            final boolean attachedInParent = attachedWindowFrame != null && !layoutInScreen;

            // TYPE_BASE_APPLICATION windows are never considered floating here because they don't
            // get cropped / shifted to the displayFrame in WindowState.
            // floatingInScreenWindow 变量判断窗口是否为非全屏窗口,同时被放置在屏幕之内,且窗口类型不是 TYPE_BASE_APPLICATION
            // 如果窗口类型不是 TYPE_BASE_APPLICATION,则可以认为该窗口是浮动窗口,需要考虑刘海屏幕问题。如果是全屏窗口,则不需要考虑刘海屏幕问题。
            final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
                    && type != TYPE_BASE_APPLICATION;

            // Windows that are attached to a parent and laid out in said parent already avoid
            // the cutout according to that parent and don't need to be further constrained.
            // Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
            // They will later be cropped or shifted using the displayFrame in WindowState,
            // which prevents overlap with the DisplayCutout.
            // 如果窗口不连接到父级,且不是浮动窗口,则可以认为窗口会被刘海屏遮挡
            // 做裁剪处理
            if (!attachedInParent && !floatingInScreenWindow) {
                mTempRect.set(outParentFrame);
                outParentFrame.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
                frames.isParentFrameClippedByDisplayCutout = !mTempRect.equals(outParentFrame);
            }
            outDisplayFrame.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
        }


        // noLimits 表示是否启用无限制的布局
        final boolean noLimits = (attrs.flags & FLAG_LAYOUT_NO_LIMITS) != 0;
        // inMultiWindowMode 表示窗口是否处于多窗口模式
        final boolean inMultiWindowMode = WindowConfiguration.inMultiWindowMode(windowingMode);

        // 启用了无限制的布局、窗口不是系统错误类型(TYPE_SYSTEM_ERROR)
        // 并且窗口不处于多窗口模式,那么将窗口的显示范围设置为整个屏幕
        if (noLimits && type != TYPE_SYSTEM_ERROR && !inMultiWindowMode) {
            outDisplayFrame.left = MIN_X;
            outDisplayFrame.top = MIN_Y;
            outDisplayFrame.right = MAX_X;
            outDisplayFrame.bottom = MAX_Y;
        }
        // compatScale 表示兼容比例
        final boolean hasCompatScale = compatScale != 1f;
        // 父级窗口的宽度和高度
        final int pw = outParentFrame.width();
        final int ph = outParentFrame.height();
        // 表示窗口是否扩展到刘海区
        final boolean extendedByCutout =
                (attrs.privateFlags & PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT) != 0;
        // 请求的窗口宽度和高度等
        int rw = requestedWidth;
        int rh = requestedHeight;
        // x,y,w,h 后面将用于计算窗口的位置和大小
        float x, y;
        int w, h;

        // 处理窗口的宽度和高度
        if (rw == UNSPECIFIED_LENGTH || extendedByCutout) {
            // 窗口的宽度和高度是UNSPECIFIED_LENGTH,且扩展到刘海区就重新计算高度
            // 计算结果为如果窗口的宽度 attrs.width 大于等于0,就使用 attrs.width 作为窗口的宽度,
            // 否则使用父容器的宽度 pw 作为窗口的宽度
            rw = attrs.width >= 0 ? attrs.width : pw;
        }
        if (rh == UNSPECIFIED_LENGTH || extendedByCutout) {
            rh = attrs.height >= 0 ? attrs.height : ph;
        }
        // 根据窗口的属性计算窗口的宽度和高度
        if ((attrs.flags & FLAG_SCALED) != 0) {
            if (attrs.width < 0) {
                w = pw;
            } else if (hasCompatScale) {
                w = (int) (attrs.width * compatScale + .5f);
            } else {
                w = attrs.width;
            }
            if (attrs.height < 0) {
                h = ph;
            } else if (hasCompatScale) {
                h = (int) (attrs.height * compatScale + .5f);
            } else {
                h = attrs.height;
            }
        } else {
            if (attrs.width == MATCH_PARENT) {
                w = pw;
            } else if (hasCompatScale) {
                w = (int) (rw * compatScale + .5f);
            } else {
                w = rw;
            }
            if (attrs.height == MATCH_PARENT) {
                h = ph;
            } else if (hasCompatScale) {
                h = (int) (rh * compatScale + .5f);
            } else {
                h = rh;
            }
        }
        // 处理是否需要缩放
        if (hasCompatScale) {
            x = attrs.x * compatScale;
            y = attrs.y * compatScale;

        } else {
            x = attrs.x;
            y = attrs.y;
        }
        // 如果窗口处于多窗口模式且不是全屏任务
        // PRIVATE_FLAG_XX标志位表示窗口是否应该布局在其父窗口的框架内,而不是在父窗口的内容内
        // 在多窗口模式下,如果子窗口不在父窗口的框架内,则需要确保它适合于父窗口的大小,因为父窗口可能是非全屏的任务
        // 所以如果满足条件则需要调整子窗口的大小以适应父窗口的大小。
        if (inMultiWindowMode
                && (attrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) == 0) {
            // Make sure window fits in parent frame since it is in a non-fullscreen task as
            // required by {@link Gravity#apply} call.
            w = Math.min(w, pw);
            h = Math.min(h, ph);
        }

        // 如果不在多窗口模式下,或者不是TYPE_BASE_APPLICATION类型,且noLimits属性为false,
        // 则需要将窗口大小限制在显示器内。fitToDisplay变量用于表示是否需要将窗口大小限制在显示器内
        final boolean fitToDisplay = !inMultiWindowMode
                || ((attrs.type != TYPE_BASE_APPLICATION) && !noLimits);

        // 计算出窗口在父视图中的矩形框的位置和大小,并将结果保存在outFrame变量中
        Gravity.apply(attrs.gravity, w, h, outParentFrame,
                (int) (x + attrs.horizontalMargin * pw),
                (int) (y + attrs.verticalMargin * ph), outFrame);

        // 计算出窗口在整个屏幕范围内的位置和大小,并将结果保存在outFrame变量中
        if (fitToDisplay) {
            Gravity.applyDisplay(attrs.gravity, outDisplayFrame, outFrame);
        }

        if (extendedByCutout) {
            extendFrameByCutout(displayCutoutSafe, outDisplayFrame, outFrame,
                    mTempRect);
        }

        if (DEBUG) Log.d(TAG, "computeFrames " + attrs.getTitle()
                + " frames=" + frames
                + " windowBounds=" + windowBounds.toShortString()
                + " requestedWidth=" + requestedWidth
                + " requestedHeight=" + requestedHeight
                + " compatScale=" + compatScale
                + " windowingMode=" + WindowConfiguration.windowingModeToString(windowingMode)
                + " displayCutoutSafe=" + displayCutoutSafe
                + " attrs=" + attrs
                + " state=" + state
                + " requestedInvisibleTypes=" + WindowInsets.Type.toString(~requestedVisibleTypes));
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
// WindowState

private final WindowFrames mWindowFrames = new WindowFrames();

void setFrames(ClientWindowFrames clientWindowFrames, int requestedWidth, int requestedHeight) {
        final WindowFrames windowFrames = mWindowFrames;
        mTmpRect.set(windowFrames.mParentFrame);
 
        windowFrames.mDisplayFrame.set(clientWindowFrames.displayFrame);
        windowFrames.mParentFrame.set(clientWindowFrames.parentFrame);
        windowFrames.mFrame.set(clientWindowFrames.frame);
 
        windowFrames.mCompatFrame.set(windowFrames.mFrame);

        if (mInvGlobalScale != 1f) {
            // Also, the scaled frame that we report to the app needs to be adjusted to be in
            // its coordinate space.
            windowFrames.mCompatFrame.scale(mInvGlobalScale);
        }
        windowFrames.setParentFrameWasClippedByDisplayCutout(
                clientWindowFrames.isParentFrameClippedByDisplayCutout);
 
        // Calculate relative frame
        windowFrames.mRelFrame.set(windowFrames.mFrame);
        WindowContainer<?> parent = getParent();
        int parentLeft = 0;
        int parentTop = 0;
        if (mIsChildWindow) {
            parentLeft = ((WindowState) parent).mWindowFrames.mFrame.left;
            parentTop = ((WindowState) parent).mWindowFrames.mFrame.top;
        } else if (parent != null) {
            final Rect parentBounds = parent.getBounds();
            parentLeft = parentBounds.left;
            parentTop = parentBounds.top;
        }
        windowFrames.mRelFrame.offsetTo(windowFrames.mFrame.left - parentLeft,
                windowFrames.mFrame.top - parentTop);
 
        if (requestedWidth != mLastRequestedWidth || requestedHeight != mLastRequestedHeight
                || !mTmpRect.equals(windowFrames.mParentFrame)) {
            mLastRequestedWidth = requestedWidth;
            mLastRequestedHeight = requestedHeight;
            windowFrames.setContentChanged(true);
        }
 
        if (mAttrs.type == TYPE_DOCK_DIVIDER) {
            if (!windowFrames.mFrame.equals(windowFrames.mLastFrame)) {
                mMovedByResize = true;
            }
        }
 
        if (mIsWallpaper) {
            final Rect lastFrame = windowFrames.mLastFrame;
            final Rect frame = windowFrames.mFrame;
            if (lastFrame.width() != frame.width() || lastFrame.height() != frame.height()) {
                mDisplayContent.mWallpaperController.updateWallpaperOffset(this, false /* sync */);
            }
        }
 
        updateSourceFrame(windowFrames.mFrame);
 
        if (mActivityRecord != null && !mIsChildWindow) {
            mActivityRecord.layoutLetterbox(this);
        }
        mSurfacePlacementNeeded = true;
        mHaveFrame = true;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// /frameworks/base/services/core/java/com/android/server/wm/WindowFrames.java

/**
 * Container class for all the window frames that affect how windows are laid out.
 *
 * TODO(b/111611553): Investigate which frames are still needed and which are duplicates
 */
public class WindowFrames {

    private static final StringBuilder sTmpSB = new StringBuilder();

    /**
     * The frame to be referenced while applying gravity and MATCH_PARENT.
     */
    public final Rect mParentFrame = new Rect();

    /**
     * The bounds that the window should fit.
     */
    public final Rect mDisplayFrame = new Rect();

    /**
     * "Real" frame that the application sees, in display coordinate space.
     */
    final Rect mFrame = new Rect();

    /**
     * The last real frame that was reported to the client.
     */
    final Rect mLastFrame = new Rect();

    /**
     * mFrame but relative to the parent container.
     */
    final Rect mRelFrame = new Rect();

    /**
     * mLastFrame but relative to the parent container
     */
    final Rect mLastRelFrame = new Rect();

    private boolean mFrameSizeChanged = false;

    // Frame that is scaled to the application's coordinate space when in
    // screen size compatibility mode.
    final Rect mCompatFrame = new Rect();

    /**
     * Whether the parent frame would have been different if there was no display cutout.
     */
    private boolean mParentFrameWasClippedByDisplayCutout;

    // ......
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

mApplySurfaceChangesTransaction

绘制完成了,去执行 performShowLocked 方法,目前还没有开始绘制,没有什么实质操作

// frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
 
    private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
        final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
        // false
        final boolean obscuredChanged = w.mObscured !=
                mTmpApplySurfaceChangesTransactionState.obscured;
        final RootWindowContainer root = mWmService.mRoot;
 
        // ......
 
        if (obscuredChanged && w.isVisible() && mWallpaperController.isWallpaperTarget(w)) { // 不进入
            // This is the wallpaper target and its obscured state changed... make sure the
            // current wallpaper's visibility has been updated accordingly.
            mWallpaperController.updateWallpaperTokens(mDisplayContent.isKeyguardLocked());
        }
 
        w.handleWindowMovedIfNeeded();
 
        final WindowStateAnimator winAnimator = w.mWinAnimator;
 
        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
        w.resetContentChanged();
 
        // Moved from updateWindowsAndWallpaperLocked().
        if (w.mHasSurface) { // 进入
            // Take care of the window being ready to display.
            // 关注点
            final boolean committed = winAnimator.commitFinishDrawingLocked(); //false
            if (isDefaultDisplay && committed) {
                if (w.hasWallpaper()) {
                    ProtoLog.v(WM_DEBUG_WALLPAPER,
                            "First draw done in potential wallpaper target %s", w);
                    mWallpaperMayChange = true;
                    pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                    if (DEBUG_LAYOUT_REPEATS) {
                        surfacePlacer.debugLayoutRepeats(
                                "wallpaper and commitFinishDrawingLocked true",
                                pendingLayoutChanges);
                    }
                }
            }
        }
 
        final ActivityRecord activity = w.mActivityRecord;
        if (activity != null && activity.isVisibleRequested()) {
            activity.updateLetterboxSurface(w);
            final boolean updateAllDrawn = activity.updateDrawnWindowStates(w);
            if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(activity)) {
                mTmpUpdateAllDrawn.add(activity);
            }
        }
 
        w.updateResizingWindowIfNeeded();
    };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    boolean commitFinishDrawingLocked() {
        if (DEBUG_STARTING_WINDOW_VERBOSE &&
                mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
            Slog.i(TAG, "commitFinishDrawingLocked: " + mWin + " cur mDrawState="
                    + drawStateToString());
        }

        // 当前是 DRAW_PENDING
        // 所以直接返回
        if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
            return false;
        }
        if (com.android.server.wm.ProtoLogCache.WM_DEBUG_ANIM_enabled) { String protoLogParam0 = String.valueOf(mSurfaceController); com.android.internal.protolog.ProtoLogImpl.i(WM_DEBUG_ANIM, -203358733, 0, null, protoLogParam0); 

        //如果已经绘制完成
        mDrawState = READY_TO_SHOW;
        boolean result = false;
        final ActivityRecord activity = mWin.mActivityRecord;
        if (activity == null || activity.canShowWindows()
                || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
            result = mWin.performShowLocked();
        }
        return result;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

接着看 prepareSurfaces 的实现。

// DisplayContent
    
    private final Transaction mPendingTransaction;

    @Override
    void prepareSurfaces() {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "prepareSurfaces");
        try {

            // 返回 DisplayContent 的成员 mPendingTransaction
            final Transaction transaction = getPendingTransaction();
            
            // 关键就是你了
            super.prepareSurfaces();


            // 把 DisplayContent 的 mPendingTransaction 成员合并到 SurfaceControl 的静态成员 GlobalTransactionWrapper 中去。
            SurfaceControl.mergeToGlobalTransaction(transaction);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

调用父类

// DisplayArea

        @Override
        void prepareSurfaces() {
            mDimmer.resetDimStates();

            // 主要关注这个,其他都是 dimmer feature 相关的,目前并为涉及,有兴趣可以查看 https://blog.csdn.net/ukynho/article/details/127551525
            super.prepareSurfaces();
            final Rect dimBounds = mDimmer.getDimBounds();
            if (dimBounds != null) {
                // Bounds need to be relative, as the dim layer is a child.
                getBounds(dimBounds);
                dimBounds.offsetTo(0 /* newLeft */, 0 /* newTop */);
            }

            // If SystemUI is dragging for recents, we want to reset the dim state so any dim layer
            // on the display level fades out.
            if (!mTransitionController.isShellTransitionsEnabled()
                    && forAllTasks(task -> !task.canAffectSystemUiFlags())) {
                mDimmer.resetDimStates();
            }

            if (dimBounds != null) {
                if (mDimmer.updateDims(getSyncTransaction())) {
                    scheduleAnimation();
                }
            }
        }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

接着调用父类 prepareSurfaces 方法:

// WindowContainer

    void prepareSurfaces() {
        // If a leash has been set when the transaction was committed, then the leash reparent has
        // been committed.
        mCommittedReparentToAnimationLeash = mSurfaceAnimator.hasLeash();
        for (int i = 0; i < mChildren.size(); i++) {
            mChildren.get(i).prepareSurfaces();
        }
    }
1
2
3
4
5
6
7
8
9
10

接着调用子节点的 prepareSurfaces 方法。层层调用,最终会调用到 WindowState 的 prepareSurfaces 方法,中间节点我们就不关心,主要看 WindowState 的 prepareSurfaces 方法,因为我们刚计算了 WindowState 的位置大小。

// WindowState
    @Override
    void prepareSurfaces() {
        mIsDimming = false;
        if (mHasSurface) {
            applyDims();

            // 好像和位置有关,看看实现
            updateSurfacePositionNonOrganized();
            // Send information to SurfaceFlinger about the priority of the current window.
            updateFrameRateSelectionPriorityIfNeeded();
            updateScaleIfNeeded();
            mWinAnimator.prepareSurfaceLocked(getSyncTransaction());
        }
        super.prepareSurfaces();
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// WindowContainor
    final void updateSurfacePositionNonOrganized() {
        // Avoid fighting with the organizer over Surface position.
        if (isOrganized()) return;
        // getSyncTransaction 返回的是 displaycontent 的 mPendingTransaction 成员
        updateSurfacePosition(getSyncTransaction());
    }
1
2
3
4
5
6
7
// WindowState
    void updateSurfacePosition(Transaction t) {
        if (mSurfaceControl == null) {
            return;
        }

        if ((mWmService.mWindowPlacerLocked.isLayoutDeferred() || isGoneForLayout())
                && !mSurfacePlacementNeeded) {
            // Since this relies on mWindowFrames, changes made while layout is deferred are
            // likely to be invalid. Similarly, if it's goneForLayout, mWindowFrames may not be
            // up-to-date and thus can't be relied on.
            return;
        }

        mSurfacePlacementNeeded = false;
        // 测量位置信息
        transformFrameToSurfacePosition(mWindowFrames.mFrame.left, mWindowFrames.mFrame.top,
                mSurfacePosition);

        if (mWallpaperScale != 1f) {
            final Rect bounds = getParentFrame();
            Matrix matrix = mTmpMatrix;
            matrix.setTranslate(mXOffset, mYOffset);
            matrix.postScale(mWallpaperScale, mWallpaperScale, bounds.exactCenterX(),
                    bounds.exactCenterY());
            matrix.getValues(mTmpMatrixArray);
            mSurfacePosition.offset(Math.round(mTmpMatrixArray[Matrix.MTRANS_X]),
                Math.round(mTmpMatrixArray[Matrix.MTRANS_Y]));
        } else {
            mSurfacePosition.offset(mXOffset, mYOffset);
        }

        // Freeze position while we're unrotated, so the surface remains at the position it was
        // prior to the rotation.
        if (!mSurfaceAnimator.hasLeash() && mPendingSeamlessRotate == null
                && !mLastSurfacePosition.equals(mSurfacePosition)) {
            final boolean frameSizeChanged = mWindowFrames.isFrameSizeChangeReported();
            final boolean surfaceInsetsChanged = surfaceInsetsChanging();
            final boolean surfaceSizeChanged = frameSizeChanged || surfaceInsetsChanged;
            mLastSurfacePosition.set(mSurfacePosition.x, mSurfacePosition.y);
            if (surfaceInsetsChanged) {
                mLastSurfaceInsets.set(mAttrs.surfaceInsets);
            }
            final boolean surfaceResizedWithoutMoveAnimation = surfaceSizeChanged
                    && mWinAnimator.getShown() && !canPlayMoveAnimation() && okToDisplay()
                    && mSyncState == SYNC_STATE_NONE;
            final ActivityRecord activityRecord = getActivityRecord();
            // If this window belongs to an activity that is relaunching due to an orientation
            // change then delay the position update until it has redrawn to avoid any flickers.
            final boolean isLetterboxedAndRelaunching = activityRecord != null
                    && activityRecord.areBoundsLetterboxed()
                    && activityRecord.mLetterboxUiController
                        .getIsRelaunchingAfterRequestedOrientationChanged();
            if (surfaceResizedWithoutMoveAnimation || isLetterboxedAndRelaunching) {
                applyWithNextDraw(mSetSurfacePositionConsumer);
            } else {
                // 位置信息配置到 Transaction 中
                mSetSurfacePositionConsumer.accept(t);
            }
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

最后就是 close,apply 事务

// WindowManagerService
    void closeSurfaceTransaction(String where) {
        try {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "closeSurfaceTransaction");
            SurfaceControl.closeTransaction();
            mWindowTracing.logState(where);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }
1
2
3
4
5
6
7
8
9
10
// surfacecontrol

    public static void closeTransaction() {
        Class var0 = SurfaceControl.class;
        synchronized(SurfaceControl.class) {
            if (sTransactionNestCount == 0L) {
                Log.e("SurfaceControl", "Call to SurfaceControl.closeTransaction without matching openTransaction");
            } else if (--sTransactionNestCount > 0L) {
                return;
            }

            sGlobalTransaction.applyGlobalTransaction(false);
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    private static class GlobalTransactionWrapper extends Transaction {
        private GlobalTransactionWrapper() {
        }

        void applyGlobalTransaction(boolean sync) {
            this.applyResizedSurfaces();
            this.notifyReparentedSurfaces();
            // native
            SurfaceControl.nativeApplyTransaction(this.mNativeObject, sync);
        }

        public void apply(boolean sync) {
            throw new RuntimeException("Global transaction must be applied from closeTransaction");
        }
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// /frameworks/base/core/jni/android_view_SurfaceControl.cpp
static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) {
    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
    transaction->apply(sync);
}
1
2
3
4
5

# 4.1.3 返回窗口信息给 App

win.fillClientWindowFramesAndConfiguration

// WindowState

    void fillClientWindowFramesAndConfiguration(ClientWindowFrames outFrames,
            MergedConfiguration outMergedConfiguration, boolean useLatestConfig,
            boolean relayoutVisible) {

        // 尺寸信息给到 App
        outFrames.frame.set(mWindowFrames.mCompatFrame); // mCompatFrame 来自 mWindowFrames.mFrame
        outFrames.displayFrame.set(mWindowFrames.mDisplayFrame);
        
        if (mInvGlobalScale != 1f) {
            outFrames.displayFrame.scale(mInvGlobalScale);
        }
        if (mLayoutAttached) {
            if (outFrames.attachedFrame == null) {
                outFrames.attachedFrame = new Rect();
            }
            outFrames.attachedFrame.set(getParentWindow().getFrame());
            if (mInvGlobalScale != 1f) {
                outFrames.attachedFrame.scale(mInvGlobalScale);
            }
        }

        outFrames.compatScale = getCompatScaleForClient();

        // Note: in the cases where the window is tied to an activity, we should not send a
        // configuration update when the window has requested to be hidden. Doing so can lead to
        // the client erroneously accepting a configuration that would have otherwise caused an
        // activity restart. We instead hand back the last reported {@link MergedConfiguration}.
        if (useLatestConfig || (relayoutVisible && (mActivityRecord == null
                || mActivityRecord.isVisibleRequested()))) {
            final Configuration globalConfig = getProcessGlobalConfiguration();
            final Configuration overrideConfig = getMergedOverrideConfiguration();
            outMergedConfiguration.setConfiguration(globalConfig, overrideConfig);
            if (outMergedConfiguration != mLastReportedConfiguration) {
                mLastReportedConfiguration.setTo(outMergedConfiguration);
            }
        } else {
            outMergedConfiguration.setTo(mLastReportedConfiguration);
        }

        // 标记已向客户端报告过配置信息
        mLastConfigReportedToClient = true;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

# 4.2 BBQ 的初始化

关注点3, updateBlastSurfaceIfNeeded

// /frameworks/base/core/java/android/view/ViewRootImpl.java

    public final Surface mSurface = new Surface();
    private final SurfaceControl mSurfaceControl = new SurfaceControl();

    void updateBlastSurfaceIfNeeded() {

        if (!mSurfaceControl.isValid()) {
            return;
        }

        if (mBlastBufferQueue != null && mBlastBufferQueue.isSameSurfaceControl(mSurfaceControl)) {
            mBlastBufferQueue.update(mSurfaceControl,
                mSurfaceSize.x, mSurfaceSize.y,
                mWindowAttributes.format);
            return;
        }

        // If the SurfaceControl has been updated, destroy and recreate the BBQ to reset the BQ and
        // BBQ states.
        if (mBlastBufferQueue != null) {
            mBlastBufferQueue.destroy();
        }

        // 关注点1
        mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
                mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);

        mBlastBufferQueue.setTransactionHangCallback(sTransactionHangCallback);
        
        // 关注点2
        Surface blastSurface = mBlastBufferQueue.createSurface();

        // 关注
        // Only call transferFrom if the surface has changed to prevent inc the generation ID and
        // causing EGL resources to be recreated.
        mSurface.transferFrom(blastSurface);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public final class BLASTBufferQueue {

    // Note: This field is accessed by native code.
    public long mNativeObject; // BLASTBufferQueue*
    
    public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height,
            @PixelFormat.Format int format) {
        this(name, true /* updateDestinationFrame */);
        update(sc, width, height, format);
    }

    public BLASTBufferQueue(String name, boolean updateDestinationFrame) {
        mNativeObject = nativeCreate(name, updateDestinationFrame);
    }


    public void update(SurfaceControl sc, int width, int height, @PixelFormat.Format int format) {
        nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format);
    }

    public Surface createSurface() {
        return nativeGetSurface(mNativeObject, false /* includeSurfaceControlHandle */);
    }

    // ......
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// /frameworks/base/core/jni/android_graphics_BLASTBufferQueue.cpp
static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName,
                          jboolean updateDestinationFrame) {
    ScopedUtfChars name(env, jName);
    sp<BLASTBufferQueue> queue = new BLASTBufferQueue(name.c_str(), updateDestinationFrame);
    queue->incStrong((void*)nativeCreate);
    return reinterpret_cast<jlong>(queue.get());
}

static void nativeUpdate(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl, jlong width,
                         jlong height, jint format) {
    sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
    queue->update(reinterpret_cast<SurfaceControl*>(surfaceControl), width, height, format);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// /frameworks/native/libs/gui/BLASTBufferQueue.cpp

BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinationFrame)
      : mSurfaceControl(nullptr),
        mSize(1, 1),
        mRequestedSize(mSize),
        mFormat(PIXEL_FORMAT_RGBA_8888),
        mTransactionReadyCallback(nullptr),
        mSyncTransaction(nullptr),
        mUpdateDestinationFrame(updateDestinationFrame) {

    createBufferQueue(&mProducer, &mConsumer);
    // since the adapter is in the client process, set dequeue timeout
    // explicitly so that dequeueBuffer will block
    mProducer->setDequeueTimeout(std::numeric_limits<int64_t>::max());

    // safe default, most producers are expected to override this
    mProducer->setMaxDequeuedBufferCount(2);
    mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,
                                                      GraphicBuffer::USAGE_HW_COMPOSER |
                                                              GraphicBuffer::USAGE_HW_TEXTURE,
                                                      1, false, this);
    static std::atomic<uint32_t> nextId = 0;
    mProducerId = nextId++;
    mName = name + "#" + std::to_string(mProducerId);
    auto consumerName = mName + "(BLAST Consumer)" + std::to_string(mProducerId);
    mQueuedBufferTrace = "QueuedBuffer - " + mName + "BLAST#" + std::to_string(mProducerId);
    mBufferItemConsumer->setName(String8(consumerName.c_str()));
    mBufferItemConsumer->setFrameAvailableListener(this);

    ComposerServiceAIDL::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
    mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
    mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers;
    mNumAcquired = 0;
    mNumFrameAvailable = 0;

    TransactionCompletedListener::getInstance()->addQueueStallListener(
            [&](const std::string& reason) {
                std::function<void(const std::string&)> callbackCopy;
                {
                    std::unique_lock _lock{mMutex};
                    callbackCopy = mTransactionHangCallback;
                }
                if (callbackCopy) callbackCopy(reason);
            },
            this);

    BQA_LOGV("BLASTBufferQueue created");
}

void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
                              int32_t format) {
    LOG_ALWAYS_FATAL_IF(surface == nullptr, "BLASTBufferQueue: mSurfaceControl must not be NULL");

    std::lock_guard _lock{mMutex};
    if (mFormat != format) {
        mFormat = format;
        mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
    }

    const bool surfaceControlChanged = !SurfaceControl::isSameSurface(mSurfaceControl, surface);
    if (surfaceControlChanged && mSurfaceControl != nullptr) {
        BQA_LOGD("Updating SurfaceControl without recreating BBQ");
    }
    bool applyTransaction = false;

    // Always update the native object even though they might have the same layer handle, so we can
    // get the updated transform hint from WM.
    mSurfaceControl = surface;
    SurfaceComposerClient::Transaction t;
    if (surfaceControlChanged) {
        t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
                   layer_state_t::eEnableBackpressure);
        applyTransaction = true;
    }
    mTransformHint = mSurfaceControl->getTransformHint();
    mBufferItemConsumer->setTransformHint(mTransformHint);
    BQA_LOGV("update width=%d height=%d format=%d mTransformHint=%d", width, height, format,
             mTransformHint);

    ui::Size newSize(width, height);
    if (mRequestedSize != newSize) {
        mRequestedSize.set(newSize);
        mBufferItemConsumer->setDefaultBufferSize(mRequestedSize.width, mRequestedSize.height);
        if (mLastBufferInfo.scalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
            // If the buffer supports scaling, update the frame immediately since the client may
            // want to scale the existing buffer to the new size.
            mSize = mRequestedSize;
            if (mUpdateDestinationFrame) {
                t.setDestinationFrame(mSurfaceControl, Rect(newSize));
                applyTransaction = true;
            }
        }
    }
    if (applyTransaction) {
        // All transactions on our apply token are one-way. See comment on mAppliedLastTransaction
        t.setApplyToken(mApplyToken).apply(false, true);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
static jobject nativeGetSurface(JNIEnv* env, jclass clazz, jlong ptr,
                                jboolean includeSurfaceControlHandle) {
    sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
    return android_view_Surface_createFromSurface(env,
                                                  queue->getSurface(includeSurfaceControlHandle));
}
1
2
3
4
5
6

看下 getSurface 都干了啥?

// /frameworks/base/core/jni/android_view_Surface.cpp
jobject android_view_Surface_createFromSurface(JNIEnv* env, const sp<Surface>& surface) {
    jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz,
            gSurfaceClassInfo.ctor, (jlong)surface.get());
    if (surfaceObj == NULL) {
        if (env->ExceptionCheck()) {
            ALOGE("Could not create instance of Surface from IGraphicBufferProducer.");
            LOGE_EX(env);
            env->ExceptionClear();
        }
        return NULL;
    }
    surface->incStrong(&sRefBaseOwner);
    return surfaceObj;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// /frameworks/native/libs/gui/BLASTBufferQueue.cpp
sp<Surface> BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) {
    std::lock_guard _lock{mMutex};
    sp<IBinder> scHandle = nullptr;
    if (includeSurfaceControlHandle && mSurfaceControl) {
        scHandle = mSurfaceControl->getHandle();
    }
    return new BBQSurface(mProducer, true, scHandle, this);
}
1
2
3
4
5
6
7
8
9
class BBQSurface : public Surface {
private:
    std::mutex mMutex;
    sp<BLASTBufferQueue> mBbq GUARDED_BY(mMutex);
    bool mDestroyed GUARDED_BY(mMutex) = false;

public:
    BBQSurface(const sp<IGraphicBufferProducer>& igbp, bool controlledByApp,
               const sp<IBinder>& scHandle, const sp<BLASTBufferQueue>& bbq)
          : Surface(igbp, controlledByApp, scHandle), mBbq(bbq) {}

    //......
}
1
2
3
4
5
6
7
8
9
10
11
12
13
Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp,
                 const sp<IBinder>& surfaceControlHandle)
      : mGraphicBufferProducer(bufferProducer),
        mCrop(Rect::EMPTY_RECT),
        mBufferAge(0),
        mGenerationNumber(0),
        mSharedBufferMode(false),
        mAutoRefresh(false),
        mAutoPrerotation(false),
        mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
        mSharedBufferHasBeenQueued(false),
        mQueriedSupportedTimestamps(false),
        mFrameTimestampsSupportsPresent(false),
        mEnableFrameTimestamps(false),
        mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>()) {
    // Initialize the ANativeWindow function pointers.
    ANativeWindow::setSwapInterval  = hook_setSwapInterval;
    ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
    ANativeWindow::cancelBuffer     = hook_cancelBuffer;
    ANativeWindow::queueBuffer      = hook_queueBuffer;
    ANativeWindow::query            = hook_query;
    ANativeWindow::perform          = hook_perform;

    ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
    ANativeWindow::cancelBuffer_DEPRECATED  = hook_cancelBuffer_DEPRECATED;
    ANativeWindow::lockBuffer_DEPRECATED    = hook_lockBuffer_DEPRECATED;
    ANativeWindow::queueBuffer_DEPRECATED   = hook_queueBuffer_DEPRECATED;

    const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
    const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;

    mReqWidth = 0;
    mReqHeight = 0;
    mReqFormat = 0;
    mReqUsage = 0;
    mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
    mDataSpace = Dataspace::UNKNOWN;
    mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
    mTransform = 0;
    mStickyTransform = 0;
    mDefaultWidth = 0;
    mDefaultHeight = 0;
    mUserWidth = 0;
    mUserHeight = 0;
    mTransformHint = 0;
    mConsumerRunningBehind = false;
    mConnectedToCpu = false;
    mProducerControlledByApp = controlledByApp;
    mSwapIntervalZero = false;
    mMaxBufferCount = NUM_BUFFER_SLOTS;
    mSurfaceControlHandle = surfaceControlHandle;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# 5. View 绘制三部曲

回顾一下,Activity 窗口显示,整体的调用链:

ViewRootImpl::setView
   ViewRootImpl::requestLayout
        ViewRootImpl::scheduleTraversals             
            ViewRootImpl.TraversalRunnable::run             -- 异步操作 
               ViewRootImpl::doTraversal
                  ViewRootImpl::performTraversals
                    ViewRootImpl::measureHierarchy                  --3 步预 measure ViewViewRootImpl::relayoutWindow                    --4 步:relayoutWindow
                        Session::relayout                               -- 远程调用,构建 SurfaceControl/Layer,测量窗口大小,Transaction 配置 Layer
                        ViewRootImpl::updateBlastSurfaceIfNeeded        -- 初始化 BLASTBufferQueue,构建 Surface         
                    ViewRootImpl::performMeasure                    --5 步:View 的 测量布局绘制  
                    ViewRootImpl::performLayout
                    ViewRootImpl::performDraw        
                    ViewRootImpl::createSyncIfNeeded                --6 步:通知 WMS,客户端已经完成绘制,可以显示 SurfaceSession.addToDisplayAsUser                           ---1 步:addWindow
   mWindowLayout.computeFrames                          ---2 步:预计算 Window 尺寸
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

从 ViewRootImpl::performTraversals 入手:

// /frameworks/base/core/java/android/view/ViewRootImpl.java

    private void performTraversals() {

        mLastPerformTraversalsSkipDrawReason = null;

        // 这个 mView 是通过 setView 方法传进来的,也就是 Activity 的根布局 DecorView,使用 final 修饰,以防在遍历过程中被修改
        final View host = mView;

        // ......

        //是否正在遍历
        mIsInTraversal = true;
        //是否需要马上绘制
        mWillDrawSoon = true;
        boolean cancelDraw = false;
        String cancelReason = null;
        boolean isSyncRequest = false;
        //视图大小改变
        boolean windowSizeMayChange = false;

        // 布局参数
        // x = 0,y = 0
        // width = -1,height = -1
        // type = BASE_APPLICATION
        // surfaceInsets (0,0,0,0)
        WindowManager.LayoutParams lp = mWindowAttributes;

        //窗口的期望宽度和高度
        int desiredWindowWidth;
        int desiredWindowHeight;

        // DecorView 是否可见
        final int viewVisibility = getHostVisibility();  // 0 也就是 VISIBLE
        
        // mFirst 表示当前窗口第一次调用 performTraversals
        // false
        final boolean viewVisibilityChanged = !mFirst
                && (mViewVisibility != viewVisibility || mNewSurfaceNeeded
                // Also check for possible double visibility update, which will make current
                // viewVisibility value equal to mViewVisibility and we may miss it.
                || mAppVisibilityChanged);

        mAppVisibilityChanged = false;

        // false
        final boolean viewUserVisibilityChanged = !mFirst &&
                ((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE));

        // false
        // 判断布局 LayoutParams 的 privateFlags 是否有 RIVATE_FLAG_OPTIMIZE_MEASURE 参数
        final boolean shouldOptimizeMeasure = shouldOptimizeMeasure(lp);

        WindowManager.LayoutParams params = null;

        // ? todo https://developer.android.google.cn/guide/practices/device-compatibility-mode?hl=zh-cn
        CompatibilityInfo compatibilityInfo =
                mDisplay.getDisplayAdjustments().getCompatibilityInfo();

        // ......

        // 用来保存窗口宽度和高度,来自于全局变量 mWinFrame,这个 mWinFrame 保存了窗口最新尺寸
        // 前面预测量 Window,窗口尺寸保存在 mWinFrame 中,预测量的结果就是屏幕尺寸
        // pixel6 上值是 (0, 0 - 1080, 2400)
        Rect frame = mWinFrame;

        //构造方法里 mFirst 赋值为 true,意思是第一次执行遍历

        if (mFirst) { // 进入

            mFullRedrawNeeded = true;
            mLayoutRequested = true;

            // 设备配置信息
            final Configuration config = getConfiguration();

            if (shouldUseDisplaySize(lp)) {
                // ......
            } else if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
                    || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
               // .....
            } else { // 走这个分支
                // After addToDisplay, the frame contains the frameHint from window manager, which
                // for most windows is going to be the same size as the result of relayoutWindow.
                // Using this here allows us to avoid remeasuring after relayoutWindow
                // 前面预测量的结果
                desiredWindowWidth = frame.width();  // 1080
                desiredWindowHeight = frame.height(); // 2400
            }

        // ......
        
        if (layoutRequested) {
            if (!mFirst) { // 不进入
                // ......
            }

            // 关注点1,以 window 想要的尺寸进行预测量 View 树
            // desiredWindowWidth 1080 前面判断得到的,来自 window 的预测量结果
            // desiredWindowHeight 2400 前面判断得到的,
            // 测量的结果保存在 ViewRootImpl 的成员 mMeasuredWidth 和 mMeasuredHeight 中,也就是 DecorView 的大小
            // shouldOptimizeMeasure false
            // Ask host how big it wants to be
            windowSizeMayChange |= measureHierarchy(host, lp, mView.getContext().getResources(),
                    desiredWindowWidth, desiredWindowHeight, shouldOptimizeMeasure);
            // 计算结果 mMeasuredWidth 1080  mMeasuredHeight 2400
        }

        // ......

       

        if (mFirst || windowShouldResize || viewVisibilityChanged || params != null
                || mForceNextWindowRelayout) { // 进入


            // ......

            mForceNextWindowRelayout = false;

            insetsPending = computesInternalInsets; //false

            if (mSurfaceHolder != null) { // 不进入
                mSurfaceHolder.mSurfaceLock.lock();
                mDrawingAllowed = true;
            }

            boolean hwInitialized = false;
            boolean dispatchApplyInsets = false;
            boolean hadSurface = mSurface.isValid();

            try {
                if (DEBUG_LAYOUT) {
                    Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" +
                            host.getMeasuredHeight() + ", params=" + params);
                }

                if (mFirst || viewVisibilityChanged) { // 进入
                    mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED;
                }

                // 关注点2,window 布局
                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);

                // ......
            } catch (RemoteException e) {
            } finally {
                if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
                    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                }
            }

            // ......
            if (!mStopped || mReportNextDraw) {
                if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()
                        || dispatchApplyInsets || updatedConfiguration) {

                    int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width,
                            lp.privateFlags);
                    int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height,
                            lp.privateFlags);

                    if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed!  mWidth="
                            + mWidth + " measuredWidth=" + host.getMeasuredWidth()
                            + " mHeight=" + mHeight
                            + " measuredHeight=" + host.getMeasuredHeight()
                            + " dispatchApplyInsets=" + dispatchApplyInsets);

                    // 关注点3,正式 Measure View 树
                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);

                    // Implementation of weights from WindowManager.LayoutParams
                    // We just grow the dimensions as needed and re-measure if
                    // needs be
                    int width = host.getMeasuredWidth();
                    int height = host.getMeasuredHeight();
                    boolean measureAgain = false;

                    if (lp.horizontalWeight > 0.0f) {
                        width += (int) ((mWidth - width) * lp.horizontalWeight);
                        childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
                                MeasureSpec.EXACTLY);
                        measureAgain = true;
                    }
                    if (lp.verticalWeight > 0.0f) {
                        height += (int) ((mHeight - height) * lp.verticalWeight);
                        childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
                                MeasureSpec.EXACTLY);
                        measureAgain = true;
                    }

                    if (measureAgain) {
                        if (DEBUG_LAYOUT) Log.v(mTag,
                                "And hey let's measure once more: width=" + width
                                + " height=" + height);
                        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                    }

                    layoutRequested = true;
                }
            }
        } else {
            // Not the first pass and no window/insets/visibility change but the window
            // may have moved and we need check that and if so to update the left and right
            // in the attach info. We translate only the window frame since on window move
            // the window manager tells us only for the new frame but the insets are the
            // same and we do not want to translate them more than once.
            maybeHandleWindowMove(frame);
        }

        // ......

        final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
        boolean triggerGlobalLayoutListener = didLayout
                || mAttachInfo.mRecomputeGlobalAttributes;
        if (didLayout) {
            // 关注点4 布局
            performLayout(lp, mWidth, mHeight);

            // By this point all views have been sized and positioned
            // We can compute the transparent area

            // ......
        }

        // .....

        if (!cancelAndRedraw) {
            // A sync was already requested before the WMS requested sync. This means we need to
            // sync the buffer, regardless if WMS wants to sync the buffer.
            if (mActiveSurfaceSyncGroup != null) {
                mSyncBuffer = true;
            }

            // 关注点6,添加显示的回调
            createSyncIfNeeded();
            notifyDrawStarted(isInWMSRequestedSync());
            mDrewOnceForSync = true;

            // If the active SSG is also requesting to sync a buffer, the following needs to happen
            // 1. Ensure we keep track of the number of active syncs to know when to disable RT
            //    RT animations that conflict with syncing a buffer.
            // 2. Add a safeguard SSG to prevent multiple SSG that sync buffers from being submitted
            //    out of order.
            if (mActiveSurfaceSyncGroup != null && mSyncBuffer) {
                updateSyncInProgressCount(mActiveSurfaceSyncGroup);
                safeguardOverlappingSyncs(mActiveSurfaceSyncGroup);
            }
        }

        if (!isViewVisible) {
            mLastPerformTraversalsSkipDrawReason = "view_not_visible";
            if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                for (int i = 0; i < mPendingTransitions.size(); ++i) {
                    mPendingTransitions.get(i).endChangingAnimations();
                }
                mPendingTransitions.clear();
            }

            if (mActiveSurfaceSyncGroup != null) {
                mActiveSurfaceSyncGroup.markSyncReady();
            }
        } else if (cancelAndRedraw) {
            mLastPerformTraversalsSkipDrawReason = cancelDueToPreDrawListener
                ? "predraw_" + mAttachInfo.mTreeObserver.getLastDispatchOnPreDrawCanceledReason()
                : "cancel_" + cancelReason;
            // Try again
            scheduleTraversals();
        } else {
            if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                for (int i = 0; i < mPendingTransitions.size(); ++i) {
                    mPendingTransitions.get(i).startChangingAnimations();
                }
                mPendingTransitions.clear();
            }
            // 关注点 5
            if (!performDraw() && mActiveSurfaceSyncGroup != null) {
                // 关注点6 触发显示回调
                mActiveSurfaceSyncGroup.markSyncReady();
            }
        }

        // .....
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284

接下来:

  • 关注点3,performMeasure
  • 关注点4,performLayout
  • 关注点5,performDraw

# 5.1 measureHierarchy,预 Measure 过程

    private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
            final Resources res, final int desiredWindowWidth, final int desiredWindowHeight,
            boolean forRootSizeOnly) {
        int childWidthMeasureSpec;
        int childHeightMeasureSpec;
        boolean windowSizeMayChange = false;

        if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag,
                "Measuring " + host + " in display " + desiredWindowWidth
                + "x" + desiredWindowHeight + "...");

        boolean goodMeasure = false;
        if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
            // On large screens, we don't want to allow dialogs to just
            // stretch to fill the entire width of the screen to display
            // one line of text.  First try doing the layout at a smaller
            // size to see if it will fit.
            final DisplayMetrics packageMetrics = res.getDisplayMetrics();
            res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
            int baseSize = 0;
            if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
                baseSize = (int)mTmpValue.getDimension(packageMetrics);
            }
            if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize
                    + ", desiredWindowWidth=" + desiredWindowWidth);
            if (baseSize != 0 && desiredWindowWidth > baseSize) {
                childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width, lp.privateFlags);
                childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height,
                        lp.privateFlags);
                performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
                        + host.getMeasuredWidth() + "," + host.getMeasuredHeight()
                        + ") from width spec: " + MeasureSpec.toString(childWidthMeasureSpec)
                        + " and height spec: " + MeasureSpec.toString(childHeightMeasureSpec));
                if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
                    goodMeasure = true;
                } else {
                    // Didn't fit in that size... try expanding a bit.
                    baseSize = (baseSize+desiredWindowWidth)/2;
                    if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize="
                            + baseSize);
                    childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width, lp.privateFlags);
                    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
                    if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
                            + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
                    if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
                        if (DEBUG_DIALOG) Log.v(mTag, "Good!");
                        goodMeasure = true;
                    }
                }
            }
        }

        if (!goodMeasure) {
            childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width,
                    lp.privateFlags);
            childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height,
                    lp.privateFlags);
            if (!forRootSizeOnly || !setMeasuredRootSizeFromSpec(
                    childWidthMeasureSpec, childHeightMeasureSpec)) {
                performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
            } else {
                // We already know how big the window should be before measuring the views.
                // We can measure the views before laying out them. This is to avoid unnecessary
                // measure.
                mViewMeasureDeferred = true;
            }
            if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
                windowSizeMayChange = true;
            }
        }

        if (DBG) {
            System.out.println("======================================");
            System.out.println("performTraversals -- after measure");
            host.debug();
        }

        return windowSizeMayChange;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

# 5.2 Measure

performMeasure

// # ViewRootImpl

    // 实际是 DecorView
    View mView;
    private int mMeasuredWidth;
    private int mMeasuredHeight;
    
    private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
        if (mView == null) {
            return;
        }
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
        try {
            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
        mMeasuredWidth = mView.getMeasuredWidth();
        mMeasuredHeight = mView.getMeasuredHeight();
        mViewMeasureDeferred = false;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

理解 MeasureSpec

# 5.2 Layout

// ViewRootImpl
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
        int desiredWindowHeight) {
    ...
    final View host = mView;
    ...
    try {
        ...
        host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
        ...
    } ...
}
1
2
3
4
5
6
7
8
9
10
11
12
// ViewGroup

@Override
public final void layout(int l, int t, int r, int b) {
   ...
        super.layout(l, t, r, b);
   ...
}
1
2
3
4
5
6
7
8
// View
public void layout(int l, int t, int r, int b) {
  ...
  int oldL = mLeft;
  int oldT = mTop;
  int oldB = mBottom;
  int oldR = mRight;
  boolean changed = isLayoutModeOptical(mParent) ? setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
  ...
  if (...) {
    onLayout(changed, l, t, r, b);
    ...
  }
  ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

setFrame(l, t, r, b) 可以理解为给 mLeft , mTop, mRight, mBottom 这四个变量赋值, 然后基本就能确定当前 View 在父视图的位置了. 这几个值构成的矩形区域就是当前 View 显示的位置,这里的具体位置都是相对与父视图的位置。

onLayout 通常是子类自定义

// DecorView
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    ...
}
1
2
3
4
5
6

DecorView 的父类是 FrameLayout:

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    layoutChildren(left, top, right, bottom, false /* no force left gravity */);
}

void layoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity) {
  final int count = getChildCount();
    ...
  for (int i = 0; i < count; i++) {
      final View child = getChildAt(i);
      if (child.getVisibility() != GONE) {
          ...
          child.layout(childLeft, childTop, childLeft + width, childTop + height);
      }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 5.3 Draw

draw 分为了软件绘制和硬件绘制:

// ViewRootImpl
    private boolean performDraw() {
        mLastPerformDrawSkippedReason = null;
        if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
            mLastPerformDrawSkippedReason = "screen_off";
            return false;
        } else if (mView == null) {
            mLastPerformDrawSkippedReason = "no_root_view";
            return false;
        }

        final boolean fullRedrawNeeded = mFullRedrawNeeded || mActiveSurfaceSyncGroup != null;
        mFullRedrawNeeded = false;

        mIsDrawing = true;
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");

        addFrameCommitCallbackIfNeeded();

        boolean usingAsyncReport = isHardwareEnabled() && mActiveSurfaceSyncGroup != null;
        if (usingAsyncReport) {
            registerCallbacksForSync(mSyncBuffer, mActiveSurfaceSyncGroup);
        } else if (mHasPendingTransactions) {
            // These callbacks are only needed if there's no sync involved and there were calls to
            // applyTransactionOnDraw. These callbacks check if the draw failed for any reason and
            // apply those transactions directly so they don't get stuck forever.
            registerCallbackForPendingTransactions();
        }
        mHasPendingTransactions = false;

        try {
            // 关注点
            boolean canUseAsync = draw(fullRedrawNeeded, usingAsyncReport && mSyncBuffer);
            if (usingAsyncReport && !canUseAsync) {
                mAttachInfo.mThreadedRenderer.setFrameCallback(null);
                usingAsyncReport = false;
            }
        } finally {
            mIsDrawing = false;
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }

        // For whatever reason we didn't create a HardwareRenderer, end any
        // hardware animations that are now dangling
        if (mAttachInfo.mPendingAnimatingRenderNodes != null) {
            final int count = mAttachInfo.mPendingAnimatingRenderNodes.size();
            for (int i = 0; i < count; i++) {
                mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators();
            }
            mAttachInfo.mPendingAnimatingRenderNodes.clear();
        }

        if (mReportNextDraw) {

            // if we're using multi-thread renderer, wait for the window frame draws
            if (mWindowDrawCountDown != null) {
                try {
                    mWindowDrawCountDown.await();
                } catch (InterruptedException e) {
                    Log.e(mTag, "Window redraw count down interrupted!");
                }
                mWindowDrawCountDown = null;
            }

            if (mAttachInfo.mThreadedRenderer != null) {
                mAttachInfo.mThreadedRenderer.setStopped(mStopped);
            }

            if (LOCAL_LOGV) {
                Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
            }

            if (mSurfaceHolder != null && mSurface.isValid()) {
                final SurfaceSyncGroup surfaceSyncGroup = mActiveSurfaceSyncGroup;
                SurfaceCallbackHelper sch = new SurfaceCallbackHelper(() ->
                        mHandler.post(() -> surfaceSyncGroup.markSyncReady()));
                mActiveSurfaceSyncGroup = null;

                SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();

                sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
            } else if (!usingAsyncReport) {
                if (mAttachInfo.mThreadedRenderer != null) {
                    mAttachInfo.mThreadedRenderer.fence();
                }
            }
        }
        if (mActiveSurfaceSyncGroup != null && !usingAsyncReport) {
            mActiveSurfaceSyncGroup.markSyncReady();
        }
        if (mPerformContentCapture) {
            performContentCaptureInitialReport();
        }
        return true;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//ViewRootImpl
    private boolean draw(boolean fullRedrawNeeded, boolean forceDraw) {
        Surface surface = mSurface;
        if (!surface.isValid()) {
            return false;
        }

        if (DEBUG_FPS) {
            trackFPS();
        }

        if (!sFirstDrawComplete) {
            synchronized (sFirstDrawHandlers) {
                sFirstDrawComplete = true;
                final int count = sFirstDrawHandlers.size();
                for (int i = 0; i< count; i++) {
                    mHandler.post(sFirstDrawHandlers.get(i));
                }
            }
        }

        scrollToRectOrFocus(null, false);

        if (mAttachInfo.mViewScrollChanged) {
            mAttachInfo.mViewScrollChanged = false;
            mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
        }

        boolean animating = mScroller != null && mScroller.computeScrollOffset();
        final int curScrollY;
        if (animating) {
            curScrollY = mScroller.getCurrY();
        } else {
            curScrollY = mScrollY;
        }
        if (mCurScrollY != curScrollY) {
            mCurScrollY = curScrollY;
            fullRedrawNeeded = true;
            if (mView instanceof RootViewSurfaceTaker) {
                ((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
            }
        }

        final float appScale = mAttachInfo.mApplicationScale;
        final boolean scalingRequired = mAttachInfo.mScalingRequired;

        final Rect dirty = mDirty;
        if (mSurfaceHolder != null) {
            // The app owns the surface, we won't draw.
            dirty.setEmpty();
            if (animating && mScroller != null) {
                mScroller.abortAnimation();
            }
            return false;
        }

        if (fullRedrawNeeded) {
            dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
        }

        if (DEBUG_ORIENTATION || DEBUG_DRAW) {
            Log.v(mTag, "Draw " + mView + "/"
                    + mWindowAttributes.getTitle()
                    + ": dirty={" + dirty.left + "," + dirty.top
                    + "," + dirty.right + "," + dirty.bottom + "} surface="
                    + surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
                    appScale + ", width=" + mWidth + ", height=" + mHeight);
        }

        mAttachInfo.mTreeObserver.dispatchOnDraw();

        int xOffset = -mCanvasOffsetX;
        int yOffset = -mCanvasOffsetY + curScrollY;
        final WindowManager.LayoutParams params = mWindowAttributes;
        final Rect surfaceInsets = params != null ? params.surfaceInsets : null;
        if (surfaceInsets != null) {
            xOffset -= surfaceInsets.left;
            yOffset -= surfaceInsets.top;

            // Offset dirty rect for surface insets.
            dirty.offset(surfaceInsets.left, surfaceInsets.top);
        }

        boolean accessibilityFocusDirty = false;
        final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable;
        if (drawable != null) {
            final Rect bounds = mAttachInfo.mTmpInvalRect;
            final boolean hasFocus = getAccessibilityFocusedRect(bounds);
            if (!hasFocus) {
                bounds.setEmpty();
            }
            if (!bounds.equals(drawable.getBounds())) {
                accessibilityFocusDirty = true;
            }
        }

        mAttachInfo.mDrawingTime =
                mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;

        boolean useAsyncReport = false;
        if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
            if (isHardwareEnabled()) { // 硬件绘制
                // If accessibility focus moved, always invalidate the root.
                boolean invalidateRoot = accessibilityFocusDirty || mInvalidateRootRequested;
                mInvalidateRootRequested = false;

                // Draw with hardware renderer.
                mIsAnimating = false;

                if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
                    mHardwareYOffset = yOffset;
                    mHardwareXOffset = xOffset;
                    invalidateRoot = true;
                }

                if (invalidateRoot) {
                    mAttachInfo.mThreadedRenderer.invalidateRoot();
                }

                dirty.setEmpty();

                // Stage the content drawn size now. It will be transferred to the renderer
                // shortly before the draw commands get send to the renderer.
                final boolean updated = updateContentDrawBounds();

                if (mReportNextDraw) {
                    // report next draw overrides setStopped()
                    // This value is re-sync'd to the value of mStopped
                    // in the handling of mReportNextDraw post-draw.
                    mAttachInfo.mThreadedRenderer.setStopped(false);
                }

                if (updated) {
                    requestDrawWindow();
                }

                useAsyncReport = true;

                if (mUpdateHdrSdrRatioInfo) {
                    mUpdateHdrSdrRatioInfo = false;
                    applyTransactionOnDraw(mTransaction.setExtendedRangeBrightness(
                            getSurfaceControl(), mRenderHdrSdrRatio, mDesiredHdrSdrRatio));
                    mAttachInfo.mThreadedRenderer.setTargetHdrSdrRatio(mRenderHdrSdrRatio);
                }

                if (forceDraw) {
                    mAttachInfo.mThreadedRenderer.forceDrawNextFrame();
                }
                mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
            } else { // 软件绘制
                // If we get here with a disabled & requested hardware renderer, something went
                // wrong (an invalidate posted right before we destroyed the hardware surface
                // for instance) so we should just bail out. Locking the surface with software
                // rendering at this point would lock it forever and prevent hardware renderer
                // from doing its job when it comes back.
                // Before we request a new frame we must however attempt to reinitiliaze the
                // hardware renderer if it's in requested state. This would happen after an
                // eglTerminate() for instance.
                if (mAttachInfo.mThreadedRenderer != null &&
                        !mAttachInfo.mThreadedRenderer.isEnabled() &&
                        mAttachInfo.mThreadedRenderer.isRequested() &&
                        mSurface.isValid()) {

                    try {
                        mAttachInfo.mThreadedRenderer.initializeIfNeeded(
                                mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
                    } catch (OutOfResourcesException e) {
                        handleOutOfResourcesException(e);
                        return false;
                    }

                    mFullRedrawNeeded = true;
                    scheduleTraversals();
                    return false;
                }

                if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
                        scalingRequired, dirty, surfaceInsets)) {
                    return false;
                }
            }
        }

        if (animating) {
            mFullRedrawNeeded = true;
            scheduleTraversals();
        }
        return useAsyncReport;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

# 参考资料